From f8b2d1e4ee321345fd3a89119115bf837408ad99 Mon Sep 17 00:00:00 2001 From: DreamSourceLab Date: Sat, 14 May 2016 10:24:44 +0800 Subject: [PATCH] Add FFT function @ DSO mode --- DSView/DSView.qrc | 11 + DSView/extdef.h | 6 + DSView/icons/about.png | Bin 954 -> 1059 bytes DSView/icons/export.png | Bin 942 -> 919 bytes DSView/icons/file.png | Bin 1012 -> 1886 bytes DSView/icons/file_dis.png | Bin 641 -> 1896 bytes DSView/icons/instant.png | Bin 1081 -> 2371 bytes DSView/icons/instant_dis.png | Bin 1263 -> 2376 bytes DSView/icons/math.png | Bin 2947 -> 5671 bytes DSView/icons/math_dis.png | Bin 2961 -> 3589 bytes DSView/icons/measure.png | Bin 1136 -> 4115 bytes DSView/icons/measure_dis.png | Bin 1002 -> 4137 bytes DSView/icons/params.png | Bin 1210 -> 3514 bytes DSView/icons/params_dis.png | Bin 1162 -> 3502 bytes DSView/icons/protocol.png | Bin 967 -> 4180 bytes DSView/icons/protocol_cn.png | Bin 1243 -> 3269 bytes DSView/icons/protocol_dis.png | Bin 931 -> 4195 bytes DSView/icons/search-bar.png | Bin 1520 -> 3679 bytes DSView/icons/search-bar_dis.png | Bin 1388 -> 3671 bytes DSView/icons/start.png | Bin 1079 -> 2183 bytes DSView/icons/start_dis.png | Bin 1351 -> 2179 bytes DSView/icons/stop.png | Bin 628 -> 2110 bytes DSView/icons/trigger.png | Bin 840 -> 4093 bytes DSView/icons/trigger_dis.png | Bin 820 -> 4101 bytes DSView/icons/wiki.png | Bin 2787 -> 3561 bytes DSView/pv/data/mathstack.cpp | 238 +++++++++++- DSView/pv/data/mathstack.h | 118 +++++- DSView/pv/dialogs/fftoptions.cpp | 254 ++++++++++++- DSView/pv/dialogs/fftoptions.h | 86 ++++- DSView/pv/dock/measuredock.cpp | 10 +- DSView/pv/mainwindow.cpp | 20 +- DSView/pv/sigsession.cpp | 61 ++- DSView/pv/sigsession.h | 7 + DSView/pv/toolbars/filebar.cpp | 2 +- DSView/pv/toolbars/samplingbar.cpp | 28 +- DSView/pv/toolbars/samplingbar.h | 3 + DSView/pv/toolbars/trigbar.cpp | 76 +++- DSView/pv/toolbars/trigbar.h | 20 +- DSView/pv/view/analogsignal.cpp | 2 +- DSView/pv/view/decodetrace.cpp | 2 +- DSView/pv/view/dsosignal.cpp | 68 ++-- DSView/pv/view/dsosignal.h | 4 +- DSView/pv/view/header.cpp | 15 +- DSView/pv/view/logicsignal.cpp | 2 +- DSView/pv/view/mathtrace.cpp | 485 +++++++++++++++++++++++- DSView/pv/view/mathtrace.h | 155 +++++++- DSView/pv/view/ruler.cpp | 2 +- DSView/pv/view/signal.cpp | 4 +- DSView/pv/view/signal.h | 2 +- DSView/pv/view/trace.cpp | 25 +- DSView/pv/view/trace.h | 7 + DSView/pv/view/view.cpp | 343 ++++++++++++----- DSView/pv/view/view.h | 38 +- DSView/pv/view/viewport.cpp | 572 ++++++++++++++++------------- DSView/pv/view/viewport.h | 10 +- libsigrok4DSL/hardware/demo/demo.c | 11 +- libsigrok4DSL/libsigrok.h | 3 +- 57 files changed, 2211 insertions(+), 479 deletions(-) mode change 100644 => 100755 DSView/icons/about.png mode change 100644 => 100755 DSView/icons/file.png mode change 100644 => 100755 DSView/icons/file_dis.png mode change 100644 => 100755 DSView/icons/instant.png mode change 100644 => 100755 DSView/icons/measure.png mode change 100644 => 100755 DSView/icons/measure_dis.png mode change 100644 => 100755 DSView/icons/params.png mode change 100644 => 100755 DSView/icons/params_dis.png mode change 100644 => 100755 DSView/icons/protocol.png mode change 100644 => 100755 DSView/icons/protocol_cn.png mode change 100644 => 100755 DSView/icons/protocol_dis.png mode change 100644 => 100755 DSView/icons/search-bar.png mode change 100644 => 100755 DSView/icons/search-bar_dis.png mode change 100644 => 100755 DSView/icons/start.png mode change 100644 => 100755 DSView/icons/stop.png mode change 100644 => 100755 DSView/icons/trigger.png mode change 100644 => 100755 DSView/icons/trigger_dis.png mode change 100644 => 100755 DSView/icons/wiki.png diff --git a/DSView/DSView.qrc b/DSView/DSView.qrc index 76bf2800..5968cc45 100644 --- a/DSView/DSView.qrc +++ b/DSView/DSView.qrc @@ -57,5 +57,16 @@ icons/start_dis_cn.png icons/settings.png darkstyle/style.qss + icons/export.png + icons/single.png + icons/single_dis.png + icons/math.png + icons/math_dis.png + icons/fft.png + icons/Blackman.png + icons/Flat_top.png + icons/Hamming.png + icons/Hann.png + icons/Rectangle.png diff --git a/DSView/extdef.h b/DSView/extdef.h index 549c0629..192bb8f3 100644 --- a/DSView/extdef.h +++ b/DSView/extdef.h @@ -29,4 +29,10 @@ #define begin_element(x) (&x[0]) #define end_element(x) (&x[countof(x)]) +enum View_type { + TIME_VIEW, + FFT_VIEW, + ALL_VIEW +}; + #endif // DSVIEW_EXTDEF_H diff --git a/DSView/icons/about.png b/DSView/icons/about.png old mode 100644 new mode 100755 index ac3890958c56d5ab27b7f7e95dd117c3439ce667..c8f40c627d26318641b74f55b2678426b57b357b GIT binary patch literal 1059 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I0wfs{c7_5;mUKs7M+SzC{oH>NS%G|oWRD45bDP46hOx7_4S6Fo+k-*%fF5lweBoc6VW5SkM7 z1{amG<{Xu1^js*JHNp7vRs-kRmf!E%`)_`+dw2DH%lq%|ReqoM`#p4z>5M{D!O{O8iEzIgSO{^xu( z;fU~?P&?x#62)_>#gD&S{(hD5m9zi4)?0dhTUE5NADq>_ji^AAN9S4%grEvy$X ze)i3bA-eTnqBKyTYT^IGS&SaqA1?A8F#faNqJXth`yYRT>gUM<3`re}Mb|PIop``k z#K&@M>w)B^;?r6OWQ2Dey}nnX(kE2cSu>jDazjf5r|@b z!>ye6nQs>37OS3r(hS-P#tl7(UqrF~czpYVzIDg71A#IXhMRUzVvXplXUO5`)c5h_ z>;~os)e_f;l9a@fRIB8oR3OD*WMF8fYhbEtU=m_zW@TVzWn!XjU}R-rz;Qa`4~mA| z{FKbJO57SMr(JLWYLEok5S*V@Ql40p%1~Zju9umYU7Va)kgAtols@~NjTBH3gQu&X J%Q~loCIH8avwHvl literal 954 zcmV;r14aCaP)004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00006VoOIv0RI600RN!9r;`8x z010qNS#tmY3ljhU3ljkVnw%H_00S;bL_t(&-tAgjZsI@?tcje2M2a9%evm-1NWwQq zU{7F<;Jra^5cUSS!Llcaxq)*7zVl%5ccO@gNSudV`+<#Yf>~h35LR1KBV<8Om3w+T z(``W#n~be>6Oe@l073{UC%*4z0n`9g0;|sWxecHdn6&^+=Xr+bdA~i+qeA=bdEP=oNJ5aDdkTGgd>jL4VD=P|g$=;eG|f>e;QjsG z2*~GBBp;#+z}(*6ZYmM*_V#uGpuPg)lc?|P?EH`t@cR1t6M(q}@*x_#ySv|$1ZcDV z>ALO($#s$k0Mm8dP9~F?8i~XRxUOpeu+~gIidrUqCGPx8DBAg60vP8)ECPeUz#yqh-X$chTqI2ezV*RiFph#Y zIe?;@ZT96?Pw!NEaq908KGbu(HJH2}Y&0xIifv>+;J z3aASq?8%EHt5CNotN@WD4xFokeRz0yJ$doz=}F-bqccfVfJ*06k;WMRMpfeR@$q<5 zBcK7m(b19f@bIv?0@8B+U%-L_Y@}N*Q7ym*;;T?AP4X$A1;itex&XxyhzkH;S z2RKhF0*Vmh_enspSZtECzi0&PVzJnqDIgfgB-xdz-#Ctwjrw#PCo5TR>P{;PB-Tbd zoz9o5jq1AosWzH;9?*5YNwThR>65YgB>BHaAVj;}UVDF_R4OI*2j=R~wA<|qlJ!+H z7edrarIK8SCdB>y{mOe}CnqOrdSoH)?(SCBr93@7RokVE;`a8|z^F>BDea=9$^u7p^{ cSvXDn0lW191`&7FfB*mh07*qoM6N<$f)ypOlK=n! diff --git a/DSView/icons/export.png b/DSView/icons/export.png index cd319389389a0689dc9bff3a6e4bdeec6ba4f1b5..57ee72ff178589904f4cfd614ebe9f9921562dff 100755 GIT binary patch delta 700 zcmV;t0z>_-2bTwsi+=?K3=Qz3RSf_D0%b`=K~!ko?U_Aq6G0G$A6u?`ra~qS9|A#v zNJxVy5Rlk)=m?zwkzbHMfGB_tYLGxOC{hX#LQdio6oB~p10#cHck z6qI(>97$vZX?ol?t^(9NB0bHr$2nzxZJ+Ah>k(-<>v2<1>j7+2fOo3*{Z;{dWm5Iu z^8v_+sQwlW)i1oE%7Pw?AY znWrGn^=<;>nSW-udjNT+DYNT}I zRgIM|l4l9Ut}Xq7AdlTEq0J&@7)ls@nYREecV-G)pWcij=-ns?~%yKe8zHF7ZW?(Y3ye$I*j3mgHVm{ac zW?(S9ye$I{xk)jV{BbI4PGlNXY1m5f8Cl)XcTo;IzP4zGSVwJ(aEejBuk$QXc252U z#W!ZH1An!32ur59A5eUQ_DWb|lrI1@DaCxm8_Z`jsoE_8@b>8t!d13jh>Hg2SS^aamB3|W`02haof4*))P zRsTbl`&|XNn=$^r4{7t<;n6Py=rGd&rcl2C0Fxa98x%EEFf=+bGCDCcD=;!TFfbm{ i;sBFO1057KR4_C;F)}(aGb=DMIxsMAk6OHweFHIH(Kev~ delta 778 zcmbQvzK(rDcRdTg3D?<;UoJ8*Fx7avIEG~0dppxML&Q;}VLz`Bx2V7LK@&&r-3xZc z=&m=>izxVFVncKM!oii;r{`~EC+OxA8cR%LzN|p70Vf5~;ZcY8m3y&_#GREgGGGo4Q z_|*hCY0IlN%pOJa>sEH0nA730)-3Z+PmdXw&ZX$a1DE_8pPreNo}1hpCp7DUx$(_A zQ(7Dt>^K`^1m?BL{CLo?(#Ywec>JI3-zMiOz5aA%ZOrGBf98a^JemCE%2i(0_f64z zw$Ev_W?Wn^E^yO?**WXCUA_AJXt(#q%!R6neM~biTok^p_hPX_TabmFT%%prvL6;K zSwA=@zq`dG`0*Cg#E-j}#43Cn*YL*qE1b5F^x|oGw7j9ebbshS&dot$6C)$@uT)Q7 z^KrlGX3-hPr$>D_TofMG=DM4E%VFhUrA_)e_e|NVG&eOFRo>gSMVHO$vG1Y!xMQ~; z@pg9~V5&PH_g*RB@cu%HmaPp!_re@_^VK)>G>P5wOW^d@eEDEwmD!wSv$f()Ka?>U ztYvOrBIg&}7@{ER!5Y*!gC(!!&WCls^wSP}4SmaftmZZU2KE^b67Mh>+k9JTdnE6H zY4eoBdIHCVWS()!tv}KJ__2V+sZ^Udqk4~{OLlKNP^iar{^lX^%?z=Pg6Eje-^i*v zzCzRBROAEA+bd_WzvP^g#-p*JIY02wmcE>G1ws`^{OVk|uLxQk=X}7p`-h}yi1P!c z;|;&xJPrSn5YE`|EyMV3)!ag8WRNi0dVN-jzTQVd20hGx13 zrn&|uA%><_rbbqV2HFNjRt5%zLQ1tL8glbfGSez?Yhdu7br7gQ5@f^VJZ4P*$8}V4 diff --git a/DSView/icons/file.png b/DSView/icons/file.png old mode 100644 new mode 100755 index 2a4715da3891cd71eea4842e56760f7ae488d5de..78c469cc13bf521c2874e3235ab4d0f9ba9c70ab GIT binary patch literal 1886 zcmXxld05iv76(s!RNV{oXYZ&7oQV%h1b_{O>jeU?RUp);#U}XSv{VpHJyUE%(%OL^gd?&& zIqX;l3utIk;MJtVR+Bd+@hpqRWYZXQzz}X_qjv3e_hK-AX3=6|*}!c*g^OA@{!kVr zdOd2%rX^5-{R?_<^#;Da31U#$Nzp6{5XoFyk8k+#I4$vPe6%{s0v^fk7pfVy&Y{sP zI*lF!$dF?>YSa4PJ%@Fc0?e&tP5eLR#Yjk?(AmJeqO?nG(Dhg_jU7(`>Zki{)v$x$ z?HQb0F;x+s8xn$ee&J@o%>Wa&m-x2MTEIm@b@a>Z+kGvr!i%*;vUI>Z`Gw+zc5jix z?j3U^6T;3~DcLRGe=v(g`y3D*RE9Aqt{p=srVuAo!gIs7&%5yS+lXQk*A+&CjVBS5ww%i$mo3b(0nq}ai>64^dNTc_M> z)%5P%XdGH<_&Zfk5f8gpH8~Kh(oXc)Zd;q0W;mI*kH70D|keVu>jNc6)E@aO?a{t6N~&o>pUu`voW+P=c{# zgG9n`>ue1kY~kRVEXpm@Kkt&QFr?0 zHyUjNYrgW7i-n-DuftP4mWAng1{wT<@qLb(NrafXKSW^h8b_)y+W1$@gZ2B8T&Mt!@31ScQ04`$wgRShNreUiwtNwI`iiiXSRRMJr&bnv!keRU(^z=Ai2( zUiypBfSWTM_hCEz8<3HYU0a`U$R_#MWm+^kYzN8qb6#QRc4^nX-%gkxx$j~!*(dY!ij{vE$=YVSjRh+6R*x0rdR;frNmKi!2Dm@o;T?( z&AN|nZ1mt3qz9w@L3fJ=`rbeY!@Mu8oI325z2M$>)bt+c0sG|eOzwvn+Or3u*Eyed z)gSTFhF$*P4e8Waz=z5eLr!f^x_(!jIy)6ZwDt#8Vp=WcFoXnJe%au$ie&CN$V=!* zEjf|*sQ30Eg611v5!h|?dE3J+lLBi-cJ;{%BXnvZsGHf-A!_)IZar(n+;E7S68Ney zYVcp9*U`RqxSW4p@!79-R!yK2kJ)lSC++!PTw(#^yrpC zuVwT-FgiRJ7z6rCLD#M)C|!{g=l{LL9$`SWFhf57(pJb+)isLX*l{Z>2YyVoF; zgtLkRjed|Tw??j355ojlfjz@dpq!J0_Mhpxdy6-`!s+(ga>*o(`Pls){kz6eYVA;p StX8c4MgRitxOdZGQs&004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$i`GZ7a@E2jVe164^xK~!ko?U=uA z(@+$~&pC+`2O?MQ&*_F)M~X4%>3){@UXSKyv$JnV32iynNtS`2fH&fGwZf(gK3&jtJNT#P7fR> zA|N7wh^=n7+dexxd*AJLcM^$2DWA_r0ueX^j)(|SsT9o4&cf8x)Ol1~S?Kju(==7n zG#}ZvZD%r>H^;}vUv*vYhQ5E$6A`iB95HjhInj4FP1A1cy8cvAlozV1-m6q9iP!-A zAl%;(u|Fr=P1CfDq9~6|)7+x>Y7Tfy$j^8`Qbf>hx52h;XFQuqrJh-q^#cHQ0H8T`0IzXB^UkNLsz5}*eE#qe z5tyEyR*sI2@&IrvRsgSQw{hoFQ4~lflLM0)0HD!mgt~7ebHKZnc+I=PqE;vXcO>Id zs1ovf){h%DbP0_z=8U_4zbNoU6*vQa(f2dd+Y1fAxb{f#0k{qN^&NT5d%?mgPzh~r zZo=H$+(WP7VOeoE?_Mda0&S-q6^lh-Wl}ZKb_4zoO-{QZFqng}QHK8Hh`vGqAtE zPehbVCX;EyFixEDa=EMlfV(`zr!UNG+qT_aSXc-Y$s3=6|M!2PtK30eR->xq#%CaM z0A^lc<}b`_^x8LO-nw=G%&al2#8X)o# z5|LFAX)yDOd)z4}cebtt03vRSi1cdR7;)Sy0C2_SM7EjxhkgP;82~;b;#!m!9@je11b{UWDL4}#sz>Y4z0hPO9+M^j iaclBE5Vs}(aqBnxb}VBr1CCGt0000ezy`AbKzYwjL4e{?JsB#oao!lE83lQDU442>-ivR9 z31Yj&v!mjeKz*|aD0R%GlnCD}Otj#)^yymqnRCC)m!HF?5Fm z!k^Vemj^uPV_%t$h@ww=EC|CmQyY%H112G&J|12R+GiJhXcW5__=ve;Y( z_BcPhcYo{Fv%^pu0WBcv z8ao+RuhjO5U{%w1?#L~lsdN&}LYor)6zf@Bd|M<9Z}Oo2Ti~2p(KbF!b^1GfaEkh8 z$H3YMr@wFFl4E;E#~5L)R9jpma0GU_OO`-OoEJjk!;AGG&#rD zEt$$oc0P%Pn0Clj^8z^0-2!y}b(^bNyN`+Y5s~}kKg%_YEM+%t)!n>%EJPGTo*J#- z8t_=$TND&toZWcQGMD@KKiL%vh>>K_n#8=AXo%7D1%qa8oM z`@7~s4+)o&3Wc2!&i!OlDnxiVOKp2w?4 z;~)RtrFQLA#&7wDAxq}{+|>I$B+3@|FHllslK8WgIF^Fa)bo1fmBezIFyQ&{HYlj$ z;ugEojB&w!sqM1*P{|^%mKPYIw;jf&#=9lIbwUT2p)sIaXwBW6as^%}3cF>{JqL!jc1Irc77E7OLaYtiR+0TS-Z|SL{qa_{~T%)+5KH(!ZnWDu~MOckukoo=(9uwV3n?1U5R8DC z3A+P<*oU!rlv2`5QE{FpqvM?=i8}W4J^0}}HS>6!{nmvxfw#QkTwyZW|LSW`*-Zi@ zA6JDn9(~L#PGX@&la>*Yu&-dqAH;fD@v1_h7hAPXxNR8r2TFUN7DbhZ zb!dfxue&CWnb=kpyVnK44_1afv)|L%GNNaH9)fzS^F-wldNy)PSZnd(JlfVSw{Wh8 zV)z(_(hmHWk38Mn4c)5KnhiQ_#Qnh^r;B6d@CL($oo4tyB(D$9GT#Jtz|2D$2I9_( g7SgA`g2fxU6<6=-wb3004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$;505pexJe&Xk0pdwSK~!ko?U+GJ z8$lF+zht-7*kaFxcrrghc(K2rz4T_VJqRu0A&CA2({qcL9(pK+UW<@RFaCni2l)rR zS;4DTgbI%9AtS61(C$urS)A{Z<*~`UZ{Ez?$=0$gqsr8+6Nm!V2}A+w1j>>Y`I4$W z2EGGtZn^cyIrq64oi zhQnd7aqnvn%mUAxb8En+bFQVTNtFbyc>=5h+dvQri!Rgv-T_@;v8;qu8*KpZfh{jl zI1kI`z*ArYSoPPH699MwECF*>6(~&gg<11^Ab5h*m2 zm9N0Vd=5+#l@|!!`&4xq_zJxAp#ktsL_SQFfbTNi?U09agH00000NkvXXu0mjf$s`0E diff --git a/DSView/icons/instant.png b/DSView/icons/instant.png old mode 100644 new mode 100755 index 2aa5c250095bba38be002808e05e6f496061278b..c3e249d3732fe960f037ce142a99a624616727a9 GIT binary patch literal 2371 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 Yy|g`#_(LBCB)0;9c5!!ZbPB)vH*2a};s5{u literal 1081 zcmV-91jhS`P)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$i`AQ5(`YBc}=1DZ)hK~!ko?O07n zTvr%9-!)Go8DEKrN|_{G*+{cVApsX@S7uc~#AGu{YlEA1T8X-`SxmBtpdi78i^9Wz zx=|#!3$+oFK$0#}T8PDMi`Y_WoN9?N9naTA-h`*j--FNRD zQB@pfn4kre3zlci)f=1p3 zYHMqcBoc|U!^6Wh<>lqR`7JFiRw9x3FcOIz55$0olpABN^!4@i#$vIfezRsFrt-_Ls^tE;Q4Bzaq1ko^h`V+pG#+gzyEQ0|3z8-hN_rb#;>D zOOp2n2L~H-A|4b20MOdndWz(=k&%&e6%`dZUuOL35kI01BHrHnz(K*GH<0!)SL{Eq z{2-#sgX(6e+UyvL_t(|ob8-#h#glM z$A8K}1))tOG-Z`dONa>y+X~h+AMAdpZW5tJOK<}*>xXkDId|^dy)$#>?oDKVFx;6l zbDnda|Gb>{f7`RLus}_DZt8XhZggq^BdG<9q!uueTEIwZ0VAmejHDJYl4VPspqbqS zd>D8?&{L7w1>gek4@p-lvYCsXPPRnMYz6QYU<|koSOt89&fU1nz&T(JcndfTye#Rx z4y9MUfM#|xV8CWz9k9I81d4MB_#JQ%kfi@sX}nSaf6Z(R*advLGNaY?YKMH&T81>r+T12@BY?1V0OuA75n%QH(6J(dBQ@|czx@xiV;zeBxJP6#K zamfPke*;NRl})3xfM)hQa9_r$8DNK`sj`{s1ZH+OFbRAv`p6r?lxw2C-7Suf9t950iTz2Ca;~MErLBXiU+W*sCd5G zGYO0k-<PV ze^SAZMAYw|0NyDXH_Za@3h?VPk-ZO(q=MIYpWBkF5HYi#0%1Mrl%(O@xy-hCGw?~` zzk&aj^!G>`nAu5SC*_-kLg&Zl;;pcHr4qI|1J@v+qlKF4E2vjRK~9Zz9htyef4ZReGA) za$F_4Y9_ty7}CC_eQ%~c?3*1+wL;659ZENe;Xvt09$aqDtTGJ4N1;al@IUJU8&%8ubp{(UV(k|QpeLD{LYpW*h z)1f>wz4F!r)18$=X7;t5af`5x#qatF8v7+H!TU0l3eMF*n|oBw%udkQe=B_kxV-~Y zG*$wqXzrz%1%@P5+KTbB7yb;a4uXF#sclyl6l;k*lsaAwJXs)qF1$eNfH#8RH-L3j zi|2WgM)9E8*On9=7d}Mu$XrKyr+rU&GEMHyPRu;b=!FJ2EGhS}W<9VTIj~-+Gr=1k z$4!GsSPo42=@K^tKCe?We~Nbn7%w6ol$@RAC*oxFs5}ikR#CgOa?Gp;H>jT;#sqjs z(w?F=>*;Nd($m}O36|ZOV3|-)@vSGBM^P_xh@@U<6G^?)E0T^1m_@zVu%>}}y>KM8 zfRWS!Mp6qHNiAR`wSbWnuF#s9e=;$%fu%^NY?@2{ zwnCR`>ADpV*w}?MhbXvepb`PiY$xz#;B{aEcn%oE zEhapM>q5E^T;B_P&&L@CP6Dq2dwskef%)}jHVq(Yt&h7A_&RPr->^^PbVfQ!K3)Ni z;yyitxOVeVU_#Qof4_Db7zpA{``t-NM_c(`)f4z}+|tzn|2r6*8^Adkjz#Rlb$2C< z_-l6KL>URr^$|>blr(QZmvz<@uRqLe~g6WI1Jkk+$yQZ$KUS5 z`+=Pq`5VSf4H@@&OPX&ktpYp>Ey;4gVZG_zrxU>k9T*8R9wEq47%DZ18_le8DN7Hz@@_0d?cB;xm{ zqTY*pnlAurB<=N2SLV$sOWrr4D*~F?Ab_uO>pN^L4H1;B>h7=9vHO#l7CijQLlC@R=LFZD{s%e36`kgZ1BL(q N002ovPDHLkV1m8!8=3$B delta 1065 zcmV+^1lIe=67LB~iBL{Q4GJ0x0000DNk~Le0000m0000m2nGNE09OL}hX4Qo32;bR za{vGi!~g&e!~vBn4jTXf00(qQO+^Ra1`!Vy4!9*A?U6~=e*?NnL_t(&f$djKXk1ko zJ;!9EWhT?;2#Wcs%Xt=p3My5EEE6)W@=GMKSeh&ng)~hFnZ=uq#6?0uaFt+oT}ZkR zvdBWn!iX6mGoYclch+sF-9&5`(n8bYB5%s5Nt&7W#<4gDF5G!@&-uRdzWdFcOG$W^ z@m#eN@Qa#(e`=#Tk9UUQK z%v;^v-7l1z1K`5|$>&L492y$BJT*0Ss#Lz~x*w8se@VVvZVrIIEhGRD029N*!&g(O z)Qcw}4GavN&gF6!8XFtG1n`QdQ#O46jFLQ6Utd4g-`^ivSXlT1z;DN`cU|`r0J9`t zmGrCM_<@`QB*T(M5{X2lt*z}cfXDdjn^jj=S7>W%>!U~{@;OOg`@R@{3<$swo;$d;Ct@{5a$R{(5!$$=gUYl`Ope|}kCU!QSZ_ea06fdDE101XWd?CI$_ zH#Rml7Y>KJ3Y92^q(=bE>gwu+`T6X3fdYDadtXbZ(_iCYzdteIRVK5x zwl+ICIr&3i0X^|R$Kc@Lxm+&ytuf}IwN}QMN88)m8|ifVomeau_?;kd1Co$PBw8|= zf6R4b%mZW0`t78A%3!D``Sf zDjtv1ah$7;iLQ|R$xAYGoMtJxlx5)Wa2#jXahz5FeIzFejYl%-ZLcVRW=T7RSNTbF zi}+7P*#;yvTWfFS^LgQ*55998Cj(%|+YT!v&jVN{nId`fgwjv=`Fy_jX^U(BMyrjQ jfoh{>pxUSzs5brtTYZ#yD5qOq00000NkvXXu0mjfUP0?Y diff --git a/DSView/icons/math.png b/DSView/icons/math.png index 59f7c5f4e46090901387ae3166e7cb87f4af3e33..dbb83a78fec272e7b6a5b1b20f0431491b6a66af 100755 GIT binary patch delta 5444 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 diff --git a/DSView/icons/math_dis.png b/DSView/icons/math_dis.png index 4021208564632738ae309a6c0bae7445f7b7b8a8..9850dd5e09f1ac5da0cd70726cc86e942c89cc38 100755 GIT binary patch delta 3345 zcmV+s4es)h7lj;1Qik-J~Bxe8JQxp8f9iuIvgW2hgs?^dzgD>U?s?w5<>5Hr7-yVw_FjAKwZ1*qT64}d=gwraS!(Dyf9iI0 z19o-P2uz3?feBF~Fd=FLCPavs$HjgSS_xqHQ=R67SY01JQ@W1o+fx#nKr z*3j5u=nLEf{G`%`m|1V&N}xCJb$9>1yUzm71f~PyfXmCwlatuCFAIQvm9_z@ColsH z0S3fAJJ1etqY%CX0|z$s{`u8`8Kq=_XN6?sjD3r4IG3BdZtAAEbut+3E-fnrlz{)=H|Ls z*=(#0T}B!NPD2t=tTDrp6#N{Kl>s&ZuK-U2{{ap~L-Ii2PBeGLf6)zi8@L`A1q=p$ z1MCl66z&~KQ}lr5q7}LgIJmjFc`x8x;7GJsw1)d7LK*}PLXFJV^RlQjJy3^+lI!F$ z;89>D(gB|Yt_Chdor4?tv_lfyg%g5^#XKUmn#J%1s4|w!IRhL0~zvCt4iZqXTAkK5!Gz3-|}p)s92t zJD6cN!ZR#r0ScS`Jf9@G_^HStF`3~?7Qgo+; z?*`y&W;V1$U5BEfI1Bh+iE>#);88$xxYsx{%eQnA_kVlpfvslN6ZkBedv0;}o85gm za0?nrV}KJ2UEI{vR7Xx7nd9!I)S?b#BYyyR3E8+O1H)42$2Qn*1O^YsFyQ0JaKA6_ z+>FqkqYF6zf0~<{_d_botB90x$RMeH4XHD|fn$^PqBFJ^f!RRHC}gz%30RU>W;vSI z#sdcwsAD)L922h z)9VnV63uh>byc=$K3a`W047(^-inb1ft$*lZ%1=de*))EjF`3nM|hW;^pp#9*>67Q(+V8 z++8Re<0+Y^x z9cU#y3itxr+|I{E$ZvPMyZ^h=irsw$T10kgq#=QKA_wUuW;QB*!pz2?1z(E5J5N&SXVP=;hz3*70;tT>VaQAN3FSYGR`z0+$Pm=O(k`zQ51bz#+-`(4R>&)y%q@!(g_pF)y5=r9m z$e7Q!SlW<8--A}_v(TncAqm`qBx(SfTi+e4TPa&0e*G*;nJ!Jk(Q{egBfJCWi9^+E2g9%eSa%>5dHhUVtx zQ%kI(^}t?0zcTe5Rpwr0e~|`(SA|bGJXT?Sf2*+EgDKb7CDi7?gy;%^iFK!)7*+SJ zD+DIqOWlc4b>FI;16z=r>b)w39mpQ97`uF~+>Sh_fY#rv~5P6%Be*{LEnq9%sXy17n+P;hv$UIj^>>#>cA2tSz}^JGlwD%@FEmTQ-_9re>@%k43x(87)oco8%3qw z69|eh9k?R)|H5$1@6dyc58J)b+dbx>fb&Oy8D=&vQI7-CA~1TFOdaq73hMx+ZS@Li zS|@~K3sDp*h`>E^)i4Nn6A^a}irU|ZLVtf`X8VV7Gf)6#gas(u^DeZhA0JthflEe>}#gOGul*EUc{q5H?b1=kH0B*th}s zrHkhCoh$4?-qYV?UJF|z}K>rfz4L#Qk6 zyp6ZFTan-ScquQ2ra5-aP7~VEfQDonkO?osiK6i*qT$;C%nfO(o5@K_f7q(m-GC$y z^a_CSe`x4MC>5Yy4Eg7_#E$Rq2-OHtoLyv|f%4wYLFz*mMQBB@DcMABk2sRRQ7GmQ z;Cgqz7QoCRRRy-)vsfSd-G}1H*8@{^prknmf{2N%irFYb=?K(`CGNf;oZC!p2sgyO zquh_dVTJ62qFy8PHnU7fm58Uje#Fe?p}F@(f41YsS6WYFaIC&IfRGfkG*%}5lAIQD zos5!nmH|;5^|?sbn~7c+5iJ-4$VpT@@p=ME8oUxcgt#e}KhH&dt|x{5r$yiCEO#QLHH4#g9;`>NIEgR|DY+eaFG5_4tcR_RgfJ}cGqdNATdW;e z>Fz7c>|Uf~zeX+xxD9x~%$AUQ7tG6uycdvXXt%uffRyv6Lp`gKcD%N&nGiLXenQj; bOo;yjyK46lM*iYl00000NkvXXu0mjfi=jb* delta 2713 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 prf@M5!Uql}ZYTW&{o5p$cVgRHOyI zy{D6rAs&C;2?_}s8pP9W!~g&T(Md!>RA}Dqm`!h6RS<@s89U%m;S{NAnqUGFLPCmQ z0W4C)8dxB9$sg#FRS`QD2@+CQ@DK6_3JZ295$mQK7D!FR0wH0{S1O{^3XbFC&db8b z$*q+y*Dh|5U+L-|oqO)gyz_DAoNJP}$naqsFd~02Yy(CFhHb!zz_1M%5g33B+u7Nf zlvI)QG=QWjNpCe8jpy^aB)!&ZwO$`20UJOkE=9zunO%#BWq02LJ_4=*zhznWsia?u z#o{eVZvp{)V`d+lS-o!tlKQ$LVmu=Ll%$Ags0$HsKO*jT&mSBdeA2ION&TmgnPtFM z8jpWV`n=U@y%7;#r@1SV>XP2cvg}4g?5Ft;fWputAZaWjzL%sd%YK%0B}L}LToi6e zqFSwvN5l_l?k7p5p+_JOci#dIl7}0)M=gLtp~0Er3+he*k|2RY@|l zM^JZ!K{PT0CTSOC1K6b9tV+#ha|)nTDs2G|lD?~Ec1hBnnf*?mwJ-<*Lq)GO;F4Yh zW*9^hIzj=MX*QcL^=ebE5txXGyTGoQy>Dily}W!9BwYo*m2}D7=YZ|=zS~m~ODcc3 z`>T@vF|++a7!P1(`;uO9_h%&)dMWIl2$-29HGq9dF9UyBpPv!6Q(zLvB<<2;QTG}F z1Ki9m1K&kN*41$ziG#ZrfC))^9Chl!6EL$((vOm!1IGIGe$FwXo%h>mcYA)DdMsiG zD$QoISSppGmlw}Mv)S}gsdNC;X!n1S$3ozV!-e0>9oE2r()m9@K5H&~1pZ$HB4RO} zR~Jv4dy?=F0W+IT!}lVh91#^@Ued3_HuPKs03`P$T+MA-cB`u~XE$5;%0ele=6-hTGEt#3Q`)6l))66#9ea78ur|3F80?GIl z;D)3*U^RKOB5BUdmeNu1j+s?}S>U#r-IX*UX)PybA;~#c4M|$>MCk-wFPurh%r<~k zGb__>>+9)JIT`hp9pQ3%UP*e&%fO+R+`Z=RGr)qG-Rz{+IZ#i!AJXOSYuyX;1oFz) zC2asJ?p{yE)qw>`bNRe>_gV_|l9}Dh$vezp;5M-8?rUA^A9VC4hjoY_tLxab>vXkI oCms?;1cr^#d0^NW5g0c91v1xsysFthJOBUy07*qoM6N<$g3}lE>i_@% diff --git a/DSView/icons/measure_dis.png b/DSView/icons/measure_dis.png old mode 100644 new mode 100755 index 8510560a6824e086cc832dd7025d2c29f4e18b40..3f152eee474dd2a7e85cbf21166381409004c8d9 GIT binary patch literal 4137 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 X7DtAJ6SVfeC=eS9M_i?u@74bRHuhQm literal 1210 zcmV;r1V#IaP)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$i`8WzoEA@2YH1RF_2K~!ko?O4xi zTvZhQzE_jRmQE12W9+6P5v&%WOf3{CDilEwrgkM35kYj3jXQ~T(Yh;w3k#)xz>F@W zx+tg{F}Nw+L<=qy+p$>1HcV{OwDx>1=G^Aa?MyQ7O)_I(4qV=y^X@(G`_7O1V<-um zS+ZdR7!epYfDwUV0~iq)Hh`fKkTfCbxTI5(c6Au?sHBg)?d&jrm!wkwP5^kYFat?N z+jcWsR7(z|@6BwVncXzAB}val`a@>+shOSixiYgeu6rymjt2^G9+NZ);2{8a-3br- z?`4uVeVhTf1Avl@WSCze`BrR@P~^gDoQlJ81dB6&>GKL9S~Mw55r@D1v!nJq*c(UO_{VPilCA*Q z;pZesT6Eow4&(bG)fWLtW1bo@h_3)#0I)~WX|xLc9kiC&D;Py90T zThNod4&b_^zW|(Usdx^+)x^YQC-^tXTSakj^xx=^r7eXvYN=aKNi$~CM_|JUm|4Zl z=FO};Z~|sFo1BKLJpe8{;0gecER!q)cw{39w4JRZ@CyNmq-rlD+~b$Ryg}fVg!Hmf zGP5~JwFp?7&OLo8xvb12x~jJYC)PH{%x1gTS}?OpBpeRvaCt6 zA*pO;rD$y35A<~aRRC{Fx-4lQ$$Db5M)C(Af0*P<5~;eRNl8Ben3Xgm=>w9?vh3Ju z5lIO&0W?TH5l28$nPel&vS#FoK(Y>?>^HOf#P#=_BB|l}a%?L&iewYOVE}J*iomJ_ z9N;+sFGR)oBFTyaje!M{RR9f1O_HS;n1gF`N_ZcLbOe=UjV#Nix2Q6zA@uriu)9C0dGz1yl2Zk*p0>hU7 Y0I{Y*zBC()R{#J207*qoM6N<$f=&V!qyPW_ diff --git a/DSView/icons/params_dis.png b/DSView/icons/params_dis.png old mode 100644 new mode 100755 index 277a326663dbfe191f2318d57672dab53db1fcc7..af2518a79d3016b5e09083dee660d0d91d47e994 GIT binary patch literal 3502 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 diff --git a/DSView/icons/protocol.png b/DSView/icons/protocol.png old mode 100644 new mode 100755 index 91423ec2215970c2839a8f586d78696ba6d53ce2..acf434e2f3c3dd55e53709aaf3ee9080d72308fc GIT binary patch literal 4180 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 Wpw`;oWFOw=8Gt004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$i`A2N&)F?#?211L#EK~!ko?U+AL z6j2n#e|I1dgIUllB*wvDpjsL_f*$~C3-}0BHa50kL+78;X4oELWup|9Xh{JZO$bDw zfy4w*F^Jx4v2WoqEV#47x@_2!ObB=0oVjP-y=U%@m>G?Xpxy~I1=Kr%rhs}UaP0-O zCRr>ZHBTt1ttS#t2}VapC6~)}0D*{LW&#`)3WbA(g@xKEuJot``Fy@xRcBN+a>uNy zK8d2Jj>0Dy|fF}Imnt@@|oU8vy&R9!+tLqkD( zd;1OGRBdFl*|vBLuxvKlHat9hGaf%YJUm!hTB>>^mL$IG*YVog+MT|>zDXbhlt>J? z1w0gy+s9d&Z31tApFSP1zrMcys=vQ~+gqDRK$<4*1}1@?GUr-i|KD|MwVh&E#WgT1MGA9sUHHHX#`X~3yDbCBcIRTSJhAEK~>*JQPg$bHPz;m zY8JY{?pioo+kuF**5V6D!@r6Dn}AwFJ3Nbh@*%bF{j;`p@f=mRceKR}l^GLQPz2sOpreZm4QlEk_U| z95J(9JB{&r3$0jyhY2Zq<^(XOs#En&G^qdpL}VVA2gX!2r>YzAol(_{sxG?NuBwix zYUr=^AArBhA~Nm5VVt|fp{mOlm01!SeGWt-B4+l$%%)T|2fPI^vrZA|0#<-I5&2l! zMG<-Igk^wdz=GqMK93s+-9sz{L2xe!f~|5%RXR$9B9Z~dyqoR;gJu>2Q4j?CE}j8G zGkfQRZMnHWbYCYz;Dxu#y+AK8665Z5Gyh7}CFIIv9C&JG1z=uI(B+ccawV2=m+b>v zA~NU_3`;^v=NxAVdrnxK`$K~2D58uD?W*dCJ6E=@WAU;*;5(Ur4^>@M)n!-nr?|Zy pxUvS)L=#s5&EEs{MpHn&@fVaMs2+~U;zx diff --git a/DSView/icons/protocol_cn.png b/DSView/icons/protocol_cn.png old mode 100644 new mode 100755 index 213fd151b5b2023cc5c565a01d7c31000bd070a3..f1af4fec243d36267a544397932c5ba138de3388 GIT binary patch literal 3269 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 FV1fz_lfeK0 diff --git a/DSView/icons/search-bar.png b/DSView/icons/search-bar.png old mode 100644 new mode 100755 index 20b94274e45735c4f05fc0fb62a11075b533a7d9..1e58096d44e309e6efab825b0200958c308c0f66 GIT binary patch literal 3679 zcmXxnc{CK<{|E3HV;kF8O7>+IA`)4%^kBjmOV+5AH3nm(v2Qb!C0mB9A(|92$d-^v z65>%K>x7}wGub_iJzqV)^ZVm-?>VpgzW3a7?;rQv)XO&J{5%po004j=Wr4Im?l1o- zZqDO2Q)r|1xB~}UxZVK(ct!pc5K#0;>=?Q5DC~gP0Yt#^uw&=>z-PS^+cdtB>w%@6N=sCZo#^XL8@ZHD*;rE;T;m*g4AVWN%6NQ?c7k z05y(@IM~`VY9K>~p@2H{*|RAeEKXS#r_O?8xhlUKMV;8GCu?o>7BsOdZ2abrFwaoX zCwRfJ(wIjm3<&*z>zv3=NN0nBG%>Y9R$U`fJhNup-Cn2wwpxN{U%FZMmMniRd)ss% zhpWErMk31CJ+mWRYhtTrOTsFG4cq!zD)J-zkbL6_*xH@u^cXu2UMxZ_%ZkKr2a&(nL8Ax^$jUwCC7H>d&z|Rc;zu7<t~z zUbNV&^M}(2%s98#5WB$H$VEE@q<4~Y%1BgKM3+Oi!@E_HP(xg`c-?w##%kav%dEse zOpy&MD-gq>TT<=|$(UDQNTDE|C;Ad^%Y9Azdcz5e#AWI&RF~w(;*5R;Qbj^DmA+ExaUEFE{vDN=Fd|GmJrdA;(_{GIcsq%RzCz|N>q1eFB1cY5xWVT6^4RJV+{j;afNFZ4g~M?e>j7=D+4b`ci=1F#fZV8fv^!0n-D5^NzYaUF1mht zZJe|s7iLD-Ck9nKQ2dt{0u3ADXLn5|FV=BTa+-u+W!Be)JGTw>MGuv*^NIR_Hr&g1=9(+X32Bd`5T;%>8Z((TPV&Qwk{kt1h1Hgpub4=?0nAuy6ac z0NQ?@T{svW1&9DpS(;ExD%r_ZlHN%0s>XLo?K~m9m(s@&Qy6-Xf45|6T>gJ%ER^xRF+U3l9>RsF&y{xH6>5Ig)92H*TI|3as?GX06 z`SMgo!!-Y9QmthsTYQzxl?Q!)n_ow?5U@V$XVI?`l$6{6WGR`+bc! zWuFGOLE`{L)ay#8Ns0AM{sWG6=Pg@b)_g=BT zvZT>8XF_{k(jhx-Rk+)11=3M_e*%|>_YKK! zv5XpHogwLt6DYDu*d0~rF{6x+%M6@)@LXwt0n(by&1QexquB5mDSM@uE8dcqpRF+kame;ABO=Kdg|!rhdaNf)pI9-`S~G5FF?1^0Y1 zSJh6c>JvU|kc^xu39Fkc60mt@?jZ3(&!XY&|%&BvC+*I6r zZ?r$_0-6TN5lXtRe@AXk`$Pl41&YyEA^{&X2~GG#A8opZ#d2hiNOGc%ilRIDb-Adl zW~ZV$#X&wtnW(Tw^+E-zn0w2OW~E_zx$0lf-)a8(OI^L&hv$LgSwNio$YV2RnYwQ zGWSi<8Kz{*MU#m!Nx~&6h(u|P4Uv4;Yeg4aJrg6P z8$@Iay}#yp>(g1uBf8_3zs~3%UG;nfu&Z38O1f5 z(THqrX(g7l+}8r_?iruIw}X^xyk|9gM=^uYF=6qgM()|wnavB0$%QY}1dZlkus#Qg zP;issIO{sf5ShS;>z*;>JBapg8D+&G|7mU(~Z0rOQH`YyW^uYC-dn zhY5PYp2E$f-*xDGY$uLRcjNK8dfj^;59L(dORk-dgg$jznicR~J+y+YC&1S37uz zNcKNVlX)+*Ut~G}dy|^td-IZ%){5yX$t)prHc4}suTEZp;H=1GPQmG$cP6|Fa=WhQ z#&iojzDe82zLu3^Yvw0mEmR=*4hIr=rgK(kjF&s?uwtab_@T|7Up*+n59U_~x>oxjBaE zy8FCk*sG2FZwU5vs$;DB_iOwr1A+cUe$KAv@^$x@q5ie`WNk~Y&{Mq^oM>7txF?>V zVc15NYsU;oMdh0Q$P3AwhxeL+#n_u9?S~%qo#}FQWiBgd@ceLdEULUM1+0RomX#Y= zsFn$@Tr?dtQ$9UqbJdsk!$o)d2@lDKZm^d z>lKzM0V&ct`-$ad9VHS^ p=XN;x11MUgTGdmHs5*ZHz*C)ivY#a-9RH&Ls7p3Tiivx|{{U^K$G`vp literal 1520 zcmV004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$i`9~f7v_^ki{1yM;vK~!ko?OAP1 zm1P*do|hv>lpz*taCRiNCO`UMp);g9TX_b|GRT!C0YCadYXQytXt<%s^3aDN>qk1* z3OCnAm~H3}I#7${!dhgwlvPVmz|$s@!ttCyeXqM8yy&|l2RVn2gB#cO?ws@NexLWc z?)!f3`+44@LmB0`hhs5-B>)xyAb@KC zu6A^ET=#mtA(5%At;Ocen`cHqAe>HTbVf!-`kp;|UIg$cfCm8R0D1xZeBi)==8}?< zGvUrZX^6xVSi^2uzmG*cI{`a5|j} zo12@ha)#WK0a!u0uXWv)z#Iluv)Dp zN~xtHGUD-gKCiE@uLsZxU}0)%>Qn31tt$fH1hA~Iu&_ke_0H1L(!YH^-}Ea8C55(a z+XkP{_rX}Y=(^tEa5xgo^Vw`Rt+BE3F_I^Zlo}veXtUYw8toZRp;fC^#l*zKI1S;w z-QC?Eoj7sgvf0Mt@i0F>|4e&(`=>Ix(OL>%1pw>xyFc_kpaEDs#`KGRaFZnu)W_z`ak2|$O^c0>C%X<>wg$OAIi$g z%1KH}x?_%AyLK%~Pfy>Vl!_9OVE}&uxIPmCLaIV#Wo3F^Uf$PsyZt$(R1AQ3T3cH$ zxLmFu09-X3V$00TeAQ~TzGU2XuC=xGN59{HBjN%8pt`#HyZ!t3H;c#%0Bp;bFaP+^ zp+nyT=)mZ9;%NXG0PYi!A-CK8<>}L>v3Kv@we9Wg-yA%6aC%cI)J|-%SX6Ow@#9{v zw~3_R=)5;bUL)xvsTSyEnJzG%7xguR(NeE4v$-|zo0 zF)^`m&6+hS>({SO0-&Edb*itfuI{g+N00V;Jf7zPJZO|sD5Y#7vcu(asgaS9Pikvx zr=CvXM!<}Ogao9erDt#elZ0OaQ8MqRmbrGVu501^L?-0pI@V!{;= z_8JHU$BrG-H*MPV)$!xUHH*bk1t3L@B2h$kY}vAfx~_-ip;Cp}vP5HtcxsXhSNBs0z9!6HMl(lmCJWagMH$uq{Mon#!zHnW}CX+g$=BUpn7 zc+f4PBGN#z(jc8_kh2F0GY&Ej8)FTIeVj4gMlvqYDI_aR&uzFHN15owmZoV#nx;Kz z97c|aNDax=BC=X3wOd3)Db=QwvIBSoM#_oE5)nBW;H0z0*Ej%n0B%jwhQ^6{r>1E` zM)aqaLO}=&0q6s8MBPR_fU^MXhTRy+@i2COjyVET!9-Q)Ryru9-UjfBrfHo3Hj2n< zQ>s*In$`#4Go{pSrBu-W1Prfl1YlQ64ThBKK@fB=G~bD53G)IXjrsFHq%kib()b^$ WCHyCCgeG$U0000OUIp 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 literal 1388 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 diff --git a/DSView/icons/start_dis.png b/DSView/icons/start_dis.png index 62eee6d588acfc5b2f0890b5291e66e7c5aac8ea..56f6e90117665371851f3fe421852cac938698eb 100755 GIT binary patch delta 1988 zcmV;#2Rr!33WE_ziBL{Q4GJ0x0000DNk~Le0000`0000`2nGNE0FDvztpET332;bR za{vGf6951U69E94oEQKA00(qQO+^Rb1q2TjCUf?U(UD2ke+N!UL_t(|ob8-#h*d=x z$A4RvLP%>+trTHGY7tQxxQ5AE8p?td6?z}=rKr#f%n!b-XjzI{e&|bq(P8HEkxPK9fo7m7kl8YD z0{BB!&jqsSMN`a~h=>dXCIORy;lN~|^uzS8*8xL; zcKaDr<&?jHX{x#*kKbGZipXN%CDQMv+kn-;j?iNHVnrPX%mXH*6e$DGtLpMbeKahf zh`bFvf01(NJ79sTZfmqsF%Xdnz{|iLDTm)t)h8RV+t5H-MCOq$-U?vkg(e<=tDFN>S0}|QifXS-5C5x?00*c5m;9JZc zufl0yysCbc#qs$@M8*K0({r4961YoM5Bl24e|ib8rl)uSPlggtM4CiosE7;>VXqdp z&ThXq5EG*}-YwAnVqZGht5mfki^CfB?*ujgHvngV^}t+J{WFC98h%#-3!UtHd>ciU z7Wj&jJ_szyaDG)pp!A~HOLj~Xn&#FE5~wJKf$ipc%IXeWD7!0}xh ze{f|={!JJW)5dT?urVxhvPavP>*Cu2A92#(sOl%4=lU?T#<6DLQxSP4puZm2SiW(x z-I!CUE1+G!d%($F<5#s{TnfAv(R zn};o!*eYCuiM=L10=7HpU9s^G-_ko%|20j8Fb@}$?pxy1X$;pnkv{Z$& zz_Y6Qbi`-OZcLkec6#}a13z}sf1^a?Vb61YI8@`<2~4YtwuEM58RcZVF{k1spsIcb z>~^wO1YDcj3H+6k|1+k)i?)DaV{o4p@3t}5CCf}?zLOpXEX#0yRaEs~;9lStn{@{G z03+Uk5I$NdH`c0TeJ;ESvsp69bX8sFZKSsSCd?AjKdM@H3>LuOe>BVwm1MK3 zx-0NiDITo%<%4x=xP;jTQK3Ju&2E>tD6nD>hi3uML(JiY>myCi7eruQ}wTc+n;&#j9R9 zi7H?k#mj~TJt&?F=cEuYe5Kk@E-7;h>S=n-zzUdor3y^)&fOjAx1EOBXn;;YXw?Vb$_Dl zEMNgJgmAMHw?0vP#Jq&3*uR~?&8m8;M%huAz+w``M@#_+)Gq=ef3gD@;iSR5Xt-BI z+JG6D;BUwLAp3!rRdr9|yqUIKC-4}i+nAd8Ue!nT(7K7)2Udb>0XEd=d)nx^v9Zm5 znr(Up<|b6h8-dvqy<0?D6Xy-FWm++7k_+i>arJyOOiTegFf9dOBCt_>f2nE{=AlrfJ6M_GcL=8MJp!zNh zQSLok1}jpUtpS+U1!kMu2%u9{2ixOItuKI`syfa&zpjr)h&qf>)f1{Z7qeZX1G8oa zFw6E?brF$f8~jmVhy7H#gKGP=KWezr8R?Umh!t`brbDkVf2CUa3bxhlz_uLBCFx#{ zY3#3aJQ#gFmD@^p|CNfp>?=&f+phm=1ias&?AD@Ep2_ zH^~k>Dace{t^J<7bDy$yn=yCLtW@)ni^Lq_Hu<*r8zNG+ z zX>bUNt_X`w&_;uLw9Prr;JDJ2xD z6(}kyGIAW(z;WEWb#-+XkH_HtLakNo;ZMMcHu?d|RFI~U2Kr_(v!+1c4Y zI5-$wSXj_(8fO_G+oP~c*_jj^h#>Wal;`Niw?4u?V^VS0M{g=%pv9G;T$^78Wc z91e%Mf3~*PZZ?}oT`t#9Fc^HMM)W)b9PoNcNy#Vm_4V&mR#w({Jf4yH`6trq>heY+ zk=Ru#rbhq(AOO{NyZuYM-TrAjp7^P|`@6dUqDqDIdKO~HgaD9!ljDpZUA$9mwgChv81b^RC!1fF}nUd{WQMS%UC zf1RDRcszc0Y;5fQ@bK_jEEd~3gFXPX3BUk=F;)QJ@0ppIfj}T|PY{GiI2``7ySrP1 z7RRGHKyh&~0Z46ZY=olG=>7iw{>b9u;%|vWVqXJ)C&JYJH|ln~KWJ!ZaL>-pj`)1O z35|T68r2gpnM_m5%gfU~pD(3_A*HCEe}LZP|Jc$SMQ1=1MGn9OW9*WA>4w#6eIQ>S z1@IZq^OFko6xSW*)B!|MGyw21#vWU(*6NpTUjksrp?|J*Sri>&Ns@d3J|v>+2P^if zsSwfIjIrDD`xFsf2M`A^0bo-$eFK>VIWkS90Ti79BDzIHQO4MWBuOMmQZvufk_8NdL*)$kqQJ&|kd7gj#iaNz8Is-h7`x3FFne->Y_?94q~=@#@Xzng9R* diff --git a/DSView/icons/stop.png b/DSView/icons/stop.png old mode 100644 new mode 100755 index 969a69994e1ef1136389b7947435353a78743317..77aa105d9f535a2f89d6aafb65464da8b78cc45e GIT binary patch literal 2110 zcmY+Fdpy(s7so%lpc(d^8A_2`D%aBTr9x~)mM9ZqhS17PGZ|$~g}Hp)zLH#`Laf~O zRVb~6a>+MxSt*y<7csfl*O2;6zsK*7-yi3k$9bODIgj__{dk{4JO|nv-id?La23VMbXE*@BQ5yyVa`V-tP>$|+949A~fg;o~b`xB?UkK+x zKO8|nN2LMfm7NY!q(GM*Ki&g>UbCc7bXBhy0yfwI{i z18E=35qsE;kw25~%SIEnw%X(h?RH+s+Jy@_G>N$Gz2}@_hEK=78-(@*1-wFus#cGj z5Bl$8?=V`6IF%Ic4I>BqVXl!kmLAt+?7&=2SB|@y>6Jy2`7|?{zi{XB?BLMt1Ln_` zJFW=1%lVe!6U%GE=AVBKAlKK|$K2kwjqWcJw9DWfOh|S#5GoU%lkUyGF$UhDr)H*o zKYlfqW2MZ1mdPC{&Z5|KL%!?l#Oxa1oQU*H#kxf(%jr)3TyBGu}Zyk$(l zM`Nkju}ep~oP2EwF#to6fo6cz3&apnxSRwe0ZY8GKb*{$++^JP-AM<`^dIAU$HCP^ zY-;IEzujPt*qk3q3TipC%BuB!xCcvBIRP=mjom6n95*WBm_U^PM7HB1BCM0ig#3V3 zCbtb?5hjlVR7#mK3Jm$2V4HtB1{Y1Mu~;R8s8AgcAwqZFdbDB+MluN7OR2f%kE4JD zz+d*6Umt%*BTb*DZ)dOHg&MuM8{w^W;fg|Vt+LxN0qjsi}ZALNJmKReJb)EM?yC3pW8m;0RL*tA$HgQtjd=!}4i zi%I%L9A_}IrIrDTWU1lC==pL83yu{^a!14zQ-q$#1{F+Uebu~k(kqCE>je?WBX2#L zs_?qC4XfJy!@q(^Phf9lFY(VeeHZteleO^Wq;`;H_lrkEmanVxn*J${{+8zxFi%GS=LpmLGHyw zPlbM@zc8qgzP?;+DYP_*M$QkBmX*A~6$?wxCx>c`jJi~gy@KfWc^DkbKDki6T#C6k zy0&j*)q1-tarATSg0sXV$ouk(iwggo;WJX^Aj&v?6j74J{=TibI+wpn?@0bP##B3r zbs~C{qfuJIp39rN40DC%PsaUZhd9rSu1%~F?exLKVcxv~x3SCz$xH3B@%l zJ~kh-BpskuouiGMUuc`?)8tXhH!%j_3C3>+O(nb)-mTwowpTywcOqydg`E6@6q7rS zLs*^tLr1t-7?0A#-OzSc+?ysEDA!OQkvr=Gn#t-xnnnj2^>&1V%=O266$fcebs_m( z$McSEkyvj_TU?|p1- zNQpH4E{~_(>q=@XI_3ErRgWuxp8!8;sej=$U{}L%5nu2WRl>FI(gSC|dHLKv)vwPF zCVq8AE(8nTC`TGK#`jRjYa%0vJ6tdkL;OlfNy|voFY>AJO&O3ynr->rug<9tDiEMl z=8jE5R9gpb0_fSdT#buO0_QrA2CjH_8jB;|L^3RSlLK79=?N;KZFO}rZjH~4M@W|5 z8b**sW8TV+CG1%1R^?2sT1N+FpP}|`dG#aA4`vV8SA2fgZeYRwfBCgn9-ug@szD>| zZo=Rq)TDC8@LdKo`|KfQGE@nosC{cW$sz9+PqPe_kvnib#}nq(FDujwYIz6W+M2~H zw>5w3{~SHL-Av6x_DfesWo`Q+I`lPLE=cz5dw@K>N7TR7Q{Kadq3qHhp`tZLKHXnp zTgQHMspoH*j}#sXkg-N*tP`0AGw-+MEL=P=k^UBgA6g^kMo_cCm#juC9-cR?wrP>H z+y04CU290-gvtq`mX8Cuga{tnh%U-2m^-ebM6mb}h6>8HLGPV@&33S;9+sVsJ;Wyv zV%`g)KnKj6NkLAN{zAu}`|@v|-7Km~LEq`XvojJomaUQAj{K zs&g~gy2aD<4={Y8Fk%kYFd=xrWBDoK(h~}w_{RtA{2VG!2rqsKe|Bx;;Q>k_oC!SE z?vhvCIbuzVFqz2dW`YWnWonNv zyI()f{IoJlRjtVBjHhv)%1gpndK4Y*d&jGHME3m!Iz9eX1ts164X1TxMofzICpF8( zfk{paXgtPcZqP=zf=9}(n#VNx-gHiBzWiLWzoW4E!rl21%$8m3I<2FP>7Tzeu|2i4 zV{i)X_cAF)(Sz=ER;{8fwE-3<{H7_4b^#A54^GmPPmc4>+=QddoEBmI8z*P%>g2wv Vu13Mr0_m9q9C6OrN;}fE{{Y>vzAXR% literal 628 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 literal 840 zcmV-O1GoH%P)004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw00006VoOIv0RI600RN!9r;`8x z010qNS#tmY4#WTe4#WYKD-Ig~000McNliru-U$i`DJm9WI9LDx0;x$vK~!ko?U*rW z6hRb*zkihkLC#>ING?KJ!B&m6SZHB&RyG!PHX?|HaKYZnS}d$g8XFr6v5JLS1k_3; zB*DV!jA$Uy_ggq(JafBu+2fYr{;+VoeK+%eH#2W$PPW<2%BnU{15|CG2B_LV4N$d# z8lY+e|2@FolHb2z`zkP=+FAz|ft!*xb_2j6NoQ<-1v-)@Z66qw`Mv;bUjn9kygn%j zpbb2-{SY`}`!=vS1b<7C9uyfYdS19d5pmh}ctkua${j=z@v6vQKO@jdzj9AW+G~3Z z*kgMg_yGI>RMh@9+5{#g9R@l@$z|8TRtP1C_rQ7J8#}9V>%cAGMnB0z1NhAWY)D!K zVyBJRUh6mazuyPCWnc`L1isnc=@e>=9KgRW*Biib+mHFRhzACcv|+nBGyq8xeVG5A zI{qPPA8@?PkFlld753dv8NDlMy2rZ{lFk7KZBGLGZGQyrODesQNm?pQ>SH6zd#3l*%hKyM6>p z14P73M7)lOzRxcs0f>m@ZLWCj?mS6NNljp?3V@zlbb@F^#DeX)O3W2_v_04qiil=J zET<{691%_1E!&-lm`OP^wmVw}u9K$OKXKcwu90qS*GHbG9jyULZ?h~rnq}E)7hnUp z13XE0c$!)lZJ)}k za)rvPLSe2S_0V1N^U4ioAWdV9#XzH`jh*V!Gt5ywAwSEF6k#uje ST3lKH0000nqmh4 diff --git a/DSView/icons/trigger_dis.png b/DSView/icons/trigger_dis.png old mode 100644 new mode 100755 index 9c804d0eb81aea468c80b574242263ef78debcc4..eb401cff315562160b57869f5f18811b853cac56 GIT binary patch literal 4101 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 literal 820 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 YWiD@WXPfRk8UO$Q07*qoM6N<$f-R5W-~a#s delta 2770 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 + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "mathstack.h" -FftStack::FftStack() +#include +#include + +#include +#include +#include +#include + +#define PI 3.1415 + +using namespace boost; +using namespace std; + +namespace pv { +namespace data { + +const QString MathStack::windows_support[5] = { + "Rectangle", + "Hann", + "Hamming", + "Blackman", + "Flat_top" +}; + +const uint64_t MathStack::length_support[5] = { + 1024, + 2048, + 4096, + 8192, + 16384, +}; + +MathStack::MathStack(pv::SigSession &session, int index) : + _session(session), + _index(index), + _dc_ignore(true), + _sample_interval(1), + _math_state(Init) +{ +} + +MathStack::~MathStack() +{ + _xn.clear(); + _xk.clear(); + _power_spectrum.clear(); + fftw_destroy_plan(_fft_plan); +} + +void MathStack::clear() { } +int MathStack::get_index() const +{ + return _index; +} + +uint64_t MathStack::get_sample_num() const +{ + return _sample_num; +} + +void MathStack::set_sample_num(uint64_t num) +{ + _sample_num = num; + _xn.resize(_sample_num); + _xk.resize(_sample_num); + _power_spectrum.resize(_sample_num/2+1); + _fft_plan = fftw_plan_r2r_1d(_sample_num, _xn.data(), _xk.data(), + FFTW_R2HC, FFTW_ESTIMATE); +} + +int MathStack::get_windows_index() const +{ + return _windows_index; +} + +void MathStack::set_windows_index(int index) +{ + _windows_index = index; +} + +bool MathStack::dc_ignored() const +{ + return _dc_ignore; +} + +void MathStack::set_dc_ignore(bool ignore) +{ + _dc_ignore = ignore; +} + +int MathStack::get_sample_interval() const +{ + return _sample_interval; +} + +void MathStack::set_sample_interval(int interval) +{ + _sample_interval = interval; +} + +const std::vector MathStack::get_windows_support() const +{ + std::vector windows; + for (size_t i = 0; i < sizeof(windows_support)/sizeof(windows_support[0]); i++) + { + windows.push_back(windows_support[i]); + } + return windows; +} + +const std::vector MathStack::get_length_support() const +{ + std::vector length; + for (size_t i = 0; i < sizeof(length_support)/sizeof(length_support[0]); i++) + { + length.push_back(length_support[i]); + } + return length; +} + +const std::vector MathStack::get_fft_spectrum() const +{ + std::vector empty; + if (_math_state == Stopped) + return _power_spectrum; + else + return empty; +} + +const double MathStack::get_fft_spectrum(uint64_t index) const +{ + if (_math_state == Stopped && index < _power_spectrum.size()) + return _power_spectrum[index]; + else + return -1; +} + +void MathStack::calc_fft() +{ + _math_state = Running; + // Get the dso data + boost::shared_ptr data; + boost::shared_ptr dsoSig; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_index() == _index && dsoSig->enabled()) { + data = dsoSig->dso_data(); + break; + } + } + } + + if (!data) + return; + + // Check we have a snapshot of data + const deque< boost::shared_ptr > &snapshots = + data->get_snapshots(); + if (snapshots.empty()) + return; + _snapshot = snapshots.front(); + + if (_snapshot->get_sample_count() < _sample_num*_sample_interval) + return; + + // Get the samplerate and start time + _start_time = data->get_start_time(); + _samplerate = data->samplerate(); + if (_samplerate == 0.0) + _samplerate = 1.0; + + // prepare _xn data + const double offset = dsoSig->get_zeroValue(); + const double vscale = dsoSig->get_vDialValue() * dsoSig->get_factor() * DS_CONF_DSO_VDIVS / (1000*255.0); + const uint16_t step = _snapshot->get_channel_num() * _sample_interval; + const uint8_t *const samples = _snapshot->get_samples(0, _sample_num*_sample_interval-1, _index); + double wsum = 0; + for (int i = 0; i < _sample_num; i++) { + double w = window(i, _windows_index); + _xn[i] = ((double)samples[i*step] - offset) * vscale * w; + wsum += w; + } + + // fft + fftw_execute(_fft_plan); + + // calculate power spectrum + _power_spectrum[0] = abs(_xk[0])/wsum; /* DC component */ + for (int k = 1; k < (_sample_num + 1) / 2; ++k) /* (k < N/2 rounded up) */ + _power_spectrum[k] = sqrt((_xk[k]*_xk[k] + _xk[_sample_num-k]*_xk[_sample_num-k]) * 2) / wsum; + if (_sample_num % 2 == 0) /* N is even */ + _power_spectrum[_sample_num/2] = abs(_xk[_sample_num/2])/wsum; /* Nyquist freq. */ + + _math_state = Stopped; +} + +double MathStack::window(uint64_t i, int type) +{ + const double n_m_1 = _sample_num-1; + switch(type) { + case 1: // Hann window + return 0.5*(1-cos(2*PI*i/n_m_1)); + case 2: // Hamming window + return 0.54-0.46*cos(2*PI*i/n_m_1); + case 3: // Blackman window + return 0.42659-0.49656*cos(2*PI*i/n_m_1) + 0.076849*cos(4*PI*i/n_m_1); + case 4: // Flat_top window + return 1-1.93*cos(2*PI*i/n_m_1)+1.29*cos(4*PI*i/n_m_1)- + 0.388*cos(6*PI*i/n_m_1)+0.028*cos(8*PI*i/n_m_1); + default: + return 1; + } +} + +} // namespace data +} // namespace pv diff --git a/DSView/pv/data/mathstack.h b/DSView/pv/data/mathstack.h index c1449463..dbbe21bc 100644 --- a/DSView/pv/data/mathstack.h +++ b/DSView/pv/data/mathstack.h @@ -1,11 +1,119 @@ -#ifndef FFTSTACK_H -#define FFTSTACK_H +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef DSVIEW_PV_DATA_MATHSTACK_H +#define DSVIEW_PV_DATA_MATHSTACK_H -class FftStack +#include "signaldata.h" + +#include + +#include +#include +#include + +#include + +#include +#include + +namespace pv { + +class SigSession; + +namespace view { +class DsoSignal; +} + +namespace data { + +class DsoSnapshot; +class Dso; + +class MathStack : public QObject, public SignalData { + Q_OBJECT + +private: + static const QString windows_support[5]; + static const uint64_t length_support[5]; + public: - FftStack(); + enum math_state { + Init, + Stopped, + Running + }; + +public: + MathStack(pv::SigSession &_session, int index); + virtual ~MathStack(); + void clear(); + + int get_index() const; + + uint64_t get_sample_num() const; + void set_sample_num(uint64_t num); + + int get_windows_index() const; + void set_windows_index(int index); + + const std::vector get_windows_support() const; + const std::vector get_length_support() const; + + bool dc_ignored() const; + void set_dc_ignore(bool ignore); + + int get_sample_interval() const; + void set_sample_interval(int interval); + + const std::vector get_fft_spectrum() const; + const double get_fft_spectrum(uint64_t index) const; + + void calc_fft(); + + double window(uint64_t i, int type); + +signals: + +private: + pv::SigSession &_session; + + int _index; + uint64_t _sample_num; + int _windows_index; + bool _dc_ignore; + int _sample_interval; + + boost::shared_ptr _snapshot; + + std::unique_ptr _math_thread; + math_state _math_state; + + fftw_plan _fft_plan; + std::vector _xn; + std::vector _xk; + std::vector _power_spectrum; }; -#endif // FFTSTACK_H +} // namespace data +} // namespace pv + +#endif // DSVIEW_PV_DATA_MATHSTACK_H diff --git a/DSView/pv/dialogs/fftoptions.cpp b/DSView/pv/dialogs/fftoptions.cpp index 576975c3..b73ac46e 100644 --- a/DSView/pv/dialogs/fftoptions.cpp +++ b/DSView/pv/dialogs/fftoptions.cpp @@ -1,7 +1,257 @@ +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + #include "fftoptions.h" -FftOptions::FftOptions() -{ +#include +#include +#include +#include + +#include "../sigsession.h" +#include "../data/mathstack.h" +#include "../view/trace.h" +#include "../view/dsosignal.h" +#include "../view/mathtrace.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace dialogs { + +FftOptions::FftOptions(QWidget *parent, SigSession &session) : + QDialog(parent), + _session(session), + _button_box(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, + Qt::Horizontal, this) +{ + _en_checkbox = new QCheckBox(this); + _len_combobox = new QComboBox(this); + _interval_combobox = new QComboBox(this); + _ch_combobox = new QComboBox(this); + _window_combobox = new QComboBox(this); + _dc_checkbox = new QCheckBox(this); + _dc_checkbox->setChecked(true); + _view_combobox = new QComboBox(this); + _dbv_combobox = new QComboBox(this); + + // setup _ch_combobox + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + _ch_combobox->addItem(dsoSig->get_name(), qVariantFromValue(dsoSig->get_index())); + } + } + + // setup _window_combobox _len_combobox + _sample_limit = 0; + GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_DSO_SAMPLELIMITS); + if (gvar != NULL) { + _sample_limit = g_variant_get_uint64(gvar) * 0.5; + g_variant_unref(gvar); + } else { + qDebug() << "ERROR: config_get SR_CONF_MAX_DSO_SAMPLELIMITS failed."; + } + std::vector windows; + std::vector length; + std::vector view_modes; + std::vector dbv_ranges; + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + windows = mathTrace->get_math_stack()->get_windows_support(); + length = mathTrace->get_math_stack()->get_length_support(); + view_modes = mathTrace->get_view_modes_support(); + dbv_ranges = mathTrace->get_dbv_ranges(); + break; + } + } + assert(windows.size() > 0); + assert(length.size() > 0); + assert(view_modes.size() > 0); + assert(dbv_ranges.size() > 0); + for (int i = 0; i < windows.size(); i++) + { + _window_combobox->addItem(windows[i], + qVariantFromValue(i)); + } + for (int i = 0; i < length.size(); i++) + { + if (length[i] < _sample_limit) + _len_combobox->addItem(QString::number(length[i]), + qVariantFromValue(length[i])); + else + break; + } + assert(_len_combobox->count() > 0); + _len_combobox->setCurrentIndex(_len_combobox->count()-1); + + const int max_interval = _sample_limit/_len_combobox->currentData().toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + for (int i = 0; i < view_modes.size(); i++) + { + _view_combobox->addItem(view_modes[i], + qVariantFromValue(i)); + } + for (int i = 0; i < dbv_ranges.size(); i++) + { + _dbv_combobox->addItem(QString::number(dbv_ranges[i]), + qVariantFromValue(dbv_ranges[i])); + } + + // load current settings + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + if (mathTrace->enabled()) { + _en_checkbox->setChecked(true); + for (int i = 0; i < _ch_combobox->count(); i++) { + if (mathTrace->get_index() == _ch_combobox->itemData(i).toInt()) { + _ch_combobox->setCurrentIndex(i); + break; + } + } + for (int i = 0; i < _len_combobox->count(); i++) { + if (mathTrace->get_math_stack()->get_sample_num() == _len_combobox->itemData(i).toLongLong()) { + _len_combobox->setCurrentIndex(i); + break; + } + } + _interval_combobox->clear(); + const int max_interval = _sample_limit/_len_combobox->currentData().toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + for (int i = 0; i < _interval_combobox->count(); i++) { + if (mathTrace->get_math_stack()->get_sample_interval() == _interval_combobox->itemData(i).toInt()) { + _interval_combobox->setCurrentIndex(i); + break; + } + } + for (int i = 0; i < _dbv_combobox->count(); i++) { + if (mathTrace->dbv_range() == _dbv_combobox->itemData(i).toLongLong()) { + _dbv_combobox->setCurrentIndex(i); + break; + } + } + _window_combobox->setCurrentIndex(mathTrace->get_math_stack()->get_windows_index()); + _dc_checkbox->setChecked(mathTrace->get_math_stack()->dc_ignored()); + _view_combobox->setCurrentIndex(mathTrace->view_mode()); + } + } + } + + _flayout = new QFormLayout(); + _flayout->addRow(new QLabel(tr("FFT Enable: "), this), _en_checkbox); + _flayout->addRow(new QLabel(tr("FFT Length: "), this), _len_combobox); + _flayout->addRow(new QLabel(tr("Sample Interval: "), this), _interval_combobox); + _flayout->addRow(new QLabel(tr("FFT Source: "), this), _ch_combobox); + _flayout->addRow(new QLabel(tr("FFT Window: "), this), _window_combobox); + _flayout->addRow(new QLabel(tr("DC Ignored: "), this), _dc_checkbox); + _flayout->addRow(new QLabel(tr("Y-axis Mode: "), this), _view_combobox); + _flayout->addRow(new QLabel(tr("DBV Range: "), this), _dbv_combobox); + + _hlayout = new QHBoxLayout(); + _hlayout->addLayout(_flayout); + _hint_label = new QLabel(this); + QString hint_pic= ":/icons/" + _window_combobox->currentText()+".png"; + QPixmap pixmap(hint_pic); + _hint_label->setPixmap(pixmap); + _hlayout->addWidget(_hint_label); + + _layout = new QVBoxLayout(this); + _layout->addLayout(_hlayout); + _layout->addWidget(&_button_box); + setLayout(_layout); + + connect(&_button_box, SIGNAL(accepted()), this, SLOT(accept())); + connect(&_button_box, SIGNAL(rejected()), this, SLOT(reject())); + connect(_window_combobox, SIGNAL(currentIndexChanged(QString)), this, SLOT(window_changed(QString))); + connect(_len_combobox, SIGNAL(currentIndexChanged(int)), this, SLOT(len_changed(int))); } +void FftOptions::accept() +{ + using namespace Qt; + + QDialog::accept(); + + BOOST_FOREACH(const boost::shared_ptr t, _session.get_math_signals()) { + boost::shared_ptr mathTrace; + if (mathTrace = dynamic_pointer_cast(t)) { + mathTrace->set_enable(false); + if (mathTrace->get_index() == _ch_combobox->currentData().toInt()) { + mathTrace->get_math_stack()->set_dc_ignore(_dc_checkbox->isChecked()); + mathTrace->get_math_stack()->set_sample_num(_len_combobox->currentData().toULongLong()); + mathTrace->get_math_stack()->set_sample_interval(_interval_combobox->currentData().toInt()); + mathTrace->get_math_stack()->set_windows_index(_window_combobox->currentData().toInt()); + mathTrace->set_view_mode(_view_combobox->currentData().toInt()); + //mathTrace->init_zoom(); + mathTrace->set_dbv_range(_dbv_combobox->currentData().toInt()); + mathTrace->set_enable(_en_checkbox->isChecked()); + if (_session.get_capture_state() == SigSession::Stopped && + mathTrace->enabled()) + mathTrace->get_math_stack()->calc_fft(); + } + } + } + _session.mathTraces_rebuild(); +} + +void FftOptions::reject() +{ + using namespace Qt; + + QDialog::reject(); +} + +void FftOptions::window_changed(QString str) +{ + QString hint_pic= ":/icons/" + str +".png"; + QPixmap pixmap(hint_pic); + _hint_label->setPixmap(pixmap); +} + +void FftOptions::len_changed(int index) +{ + int pre_index = _interval_combobox->currentIndex(); + _interval_combobox->clear(); + const int max_interval = _sample_limit/_len_combobox->itemData(index).toLongLong(); + for (int i = 1; i <= max_interval; i*=2) + { + _interval_combobox->addItem(QString::number(i), + qVariantFromValue(i)); + } + _interval_combobox->setCurrentIndex(pre_index); +} + +} // namespace dialogs +} // namespace pv diff --git a/DSView/pv/dialogs/fftoptions.h b/DSView/pv/dialogs/fftoptions.h index 618c0618..534ef3e0 100644 --- a/DSView/pv/dialogs/fftoptions.h +++ b/DSView/pv/dialogs/fftoptions.h @@ -1,11 +1,87 @@ -#ifndef FFTOPTIONS_H -#define FFTOPTIONS_H +/* + * This file is part of the DSView project. + * DSView is based on PulseView. + * + * Copyright (C) 2012 Joel Holdsworth + * Copyright (C) 2013 DreamSourceLab + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ -class FftOptions +#ifndef DSVIEW_PV_FFTOPTIONS_H +#define DSVIEW_PV_FFTOPTIONS_H + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../device/devinst.h" + +namespace pv { + +class SigSession; + +namespace dialogs { + +class FftOptions : public QDialog { + Q_OBJECT + +private: + + public: - FftOptions(); + FftOptions(QWidget *parent, SigSession &session); + +protected: + void accept(); + void reject(); + +private slots: + void window_changed(QString str); + void len_changed(int index); + +private: + SigSession &_session; + uint64_t _sample_limit; + + QComboBox *_len_combobox; + QComboBox *_interval_combobox; + QCheckBox *_en_checkbox; + QComboBox *_ch_combobox; + QComboBox *_window_combobox; + QCheckBox *_dc_checkbox; + QComboBox *_view_combobox; + QComboBox *_dbv_combobox; + + QLabel *_hint_label; + QFormLayout *_flayout; + QHBoxLayout *_hlayout; + QVBoxLayout *_layout; + QDialogButtonBox _button_box; + }; -#endif // FFTOPTIONS_H +} // namespace dialogs +} // namespace pv + +#endif // DSVIEW_PV_FFTOPTIONS_H diff --git a/DSView/pv/dock/measuredock.cpp b/DSView/pv/dock/measuredock.cpp index 6a329021..c49f0743 100644 --- a/DSView/pv/dock/measuredock.cpp +++ b/DSView/pv/dock/measuredock.cpp @@ -134,7 +134,7 @@ MeasureDock::MeasureDock(QWidget *parent, View &view, SigSession &session) : connect(_t3_comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(delta_update())); connect(_fen_checkBox, SIGNAL(stateChanged(int)), &_view, SLOT(set_measure_en(int))); - connect(_view.get_viewport(), SIGNAL(measure_updated()), this, SLOT(measure_updated())); + connect(&_view, SIGNAL(measure_updated()), this, SLOT(measure_updated())); this->setWidget(_widget); _widget->setGeometry(0, 0, sizeHint().width(), 2000); @@ -222,10 +222,10 @@ void MeasureDock::cursor_update() void MeasureDock::measure_updated() { - _width_label->setText(_view.get_viewport()->get_measure("width")); - _period_label->setText(_view.get_viewport()->get_measure("period")); - _freq_label->setText(_view.get_viewport()->get_measure("frequency")); - _duty_label->setText(_view.get_viewport()->get_measure("duty")); + _width_label->setText(_view.get_measure("width")); + _period_label->setText(_view.get_measure("period")); + _freq_label->setText(_view.get_measure("frequency")); + _duty_label->setText(_view.get_measure("duty")); } void MeasureDock::cursor_moved() diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index 90417108..0806142a 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -112,6 +112,7 @@ void MainWindow::setup_ui() { setObjectName(QString::fromUtf8("MainWindow")); setMinimumHeight(680); + setMinimumWidth(300); resize(1024, 768); // Set the window icon @@ -129,7 +130,7 @@ void MainWindow::setup_ui() // Setup the sampling bar _sampling_bar = new toolbars::SamplingBar(_session, this); - _trig_bar = new toolbars::TrigBar(this); + _trig_bar = new toolbars::TrigBar(_session, this); _file_bar = new toolbars::FileBar(_session, this); _logo_bar = new toolbars::LogoBar(_session, this); @@ -295,18 +296,8 @@ void MainWindow::update_device_list() #ifdef ENABLE_DECODE _protocol_widget->del_all_protocol(); #endif - _trig_bar->close_all(); - - if (_session.get_device()->dev_inst()->mode == LOGIC) { - _trig_bar->enable_protocol(true); - } else { - _trig_bar->enable_protocol(false); - } - if (_session.get_device()->dev_inst()->mode == DSO) { - _sampling_bar->enable_toggle(false); - } else { - _sampling_bar->enable_toggle(true); - } + _trig_bar->reload(); + _sampling_bar->reload(); shared_ptr selected_device = _session.get_device(); _device_manager.add_device(selected_device); @@ -534,8 +525,7 @@ void MainWindow::closeEvent(QCloseEvent *event) void MainWindow::on_protocol(bool visible) { #ifdef ENABLE_DECODE - if (_session.get_device()->dev_inst()->mode == LOGIC) - _protocol_dock->setVisible(visible); + _protocol_dock->setVisible(visible); #endif } diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 8b0802cf..e0b443df 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -42,12 +42,14 @@ #include "data/decoderstack.h" #include "data/decode/decoder.h" #include "data/decodermodel.h" +#include "data/mathstack.h" #include "view/analogsignal.h" #include "view/dsosignal.h" #include "view/logicsignal.h" #include "view/groupsignal.h" #include "view/decodetrace.h" +#include "view/mathtrace.h" #include #include @@ -496,7 +498,6 @@ set< boost::shared_ptr > SigSession::get_data() const assert(sig); data.insert(sig->data()); } - data.insert(_group_data); return data; } @@ -605,6 +606,12 @@ void SigSession::read_sample_rate(const sr_dev_inst *const sdi) assert(data); data->set_samplerate(sample_rate); } + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + m->get_math_stack()->set_samplerate(sample_rate); + } + _group_data->set_samplerate(sample_rate); } void SigSession::feed_in_header(const sr_dev_inst *sdi) @@ -791,10 +798,10 @@ void SigSession::init_signals() _signals.clear(); vector< boost::shared_ptr >().swap(_signals); _signals = sigs; - - signals_changed(); - data_updated(); } + + mathTraces_rebuild(); + data_updated(); } void SigSession::reload() @@ -854,7 +861,7 @@ void SigSession::reload() _signals = sigs; } - signals_changed(); + mathTraces_rebuild(); } void SigSession::refresh(int holdtime) @@ -1009,6 +1016,14 @@ void SigSession::feed_in_dso(const sr_datafeed_dso &dso) return; } + // reset scale of dso signal + BOOST_FOREACH(const boost::shared_ptr m, _math_traces) + { + assert(m); + if (m->enabled()) + m->get_math_stack()->calc_fft(); + } + receive_data(dso.num_samples); data_updated(); //if (!_instant) @@ -1401,7 +1416,41 @@ pv::data::DecoderModel* SigSession::get_decoder_model() const { return _decoder_model; } - #endif +void SigSession::mathTraces_rebuild() +{ + bool has_dso_signal = false; + BOOST_FOREACH(const boost::shared_ptr s, _signals) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + has_dso_signal = true; + // check already have + std::vector< boost::shared_ptr >::iterator iter = _math_traces.begin(); + for(int i = 0; i < _math_traces.size(); i++, iter++) + if ((*iter)->get_index() == dsoSig->get_index()) + break; + // if not, rebuild + if (iter == _math_traces.end()) { + boost::shared_ptr math_stack( + new data::MathStack(*this, dsoSig->get_index())); + boost::shared_ptr math_trace( + new view::MathTrace(*this, math_stack, dsoSig->get_index())); + _math_traces.push_back(math_trace); + } + } + } + + if (!has_dso_signal) + _math_traces.clear(); + + signals_changed(); +} + +vector< boost::shared_ptr > SigSession::get_math_signals() +{ + lock_guard lock(_signals_mutex); + return _math_traces; +} + } // namespace pv diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index de159f17..9005ab7f 100644 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -78,6 +78,7 @@ namespace view { class Signal; class GroupSignal; class DecodeTrace; +class MathTrace; } namespace decoder { @@ -157,6 +158,9 @@ public: pv::data::DecoderModel* get_decoder_model() const; + std::vector< boost::shared_ptr > + get_math_signals(); + #endif void init_signals(); @@ -178,6 +182,8 @@ public: bool get_data_lock(); + void mathTraces_rebuild(); + private: void set_capture_state(capture_state state); @@ -239,6 +245,7 @@ private: std::vector< boost::shared_ptr > _decode_traces; pv::data::DecoderModel *_decoder_model; #endif + std::vector< boost::shared_ptr > _math_traces; mutable boost::mutex _data_mutex; boost::shared_ptr _logic_data; diff --git a/DSView/pv/toolbars/filebar.cpp b/DSView/pv/toolbars/filebar.cpp index 5562db7a..cd7e0d94 100644 --- a/DSView/pv/toolbars/filebar.cpp +++ b/DSView/pv/toolbars/filebar.cpp @@ -96,7 +96,7 @@ FileBar::FileBar(SigSession &session, QWidget *parent) : _action_export = new QAction(this); _action_export->setText(QApplication::translate("File", "&Export...", 0)); - _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/instant.png"))); + _action_export->setIcon(QIcon::fromTheme("file",QIcon(":/icons/export.png"))); _action_export->setObjectName(QString::fromUtf8("actionExport")); connect(_action_export, SIGNAL(triggered()), this, SLOT(on_actionExport_triggered())); diff --git a/DSView/pv/toolbars/samplingbar.cpp b/DSView/pv/toolbars/samplingbar.cpp index ed758736..466e382d 100644 --- a/DSView/pv/toolbars/samplingbar.cpp +++ b/DSView/pv/toolbars/samplingbar.cpp @@ -154,8 +154,8 @@ SamplingBar::SamplingBar(SigSession &session, QWidget *parent) : addWidget(&_sample_count); addWidget(new QLabel(tr(" @ "))); addWidget(&_sample_rate); - addWidget(&_run_stop_button); - addWidget(&_instant_button); + _run_stop_action = addWidget(&_run_stop_button); + _instant_action = addWidget(&_instant_button); } void SamplingBar::set_device_list( @@ -785,5 +785,29 @@ void SamplingBar::show_session_error( msg.exec(); } +void SamplingBar::reload() +{ + if (_session.get_device()->dev_inst()->mode == LOGIC) { + _icon_instant = QIcon(":/icons/instant.png"); + _icon_instant_dis = QIcon(":/icons/instant_dis.png"); + _instant_button.setIcon(_icon_instant); + _run_stop_action->setVisible(true); + _instant_action->setVisible(true); + enable_toggle(true); + } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + _run_stop_action->setVisible(true); + _instant_action->setVisible(false); + enable_toggle(true); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _icon_instant = QIcon(":/icons/single.png"); + _icon_instant_dis = QIcon(":/icons/single_dis.png"); + _instant_button.setIcon(_icon_instant); + _run_stop_action->setVisible(true); + _instant_action->setVisible(true); + enable_toggle(false); + } + update(); +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/samplingbar.h b/DSView/pv/toolbars/samplingbar.h index 4055a1af..ad48c179 100644 --- a/DSView/pv/toolbars/samplingbar.h +++ b/DSView/pv/toolbars/samplingbar.h @@ -120,6 +120,7 @@ private slots: public slots: void on_configure(); void zero_adj(); + void reload(); private: SigSession &_session; @@ -145,6 +146,8 @@ private: QIcon _icon_instant_dis; QToolButton _run_stop_button; QToolButton _instant_button; + QAction* _run_stop_action; + QAction* _instant_action; bool _instant; }; diff --git a/DSView/pv/toolbars/trigbar.cpp b/DSView/pv/toolbars/trigbar.cpp index 143f9a30..bbd580a2 100644 --- a/DSView/pv/toolbars/trigbar.cpp +++ b/DSView/pv/toolbars/trigbar.cpp @@ -22,19 +22,27 @@ #include "trigbar.h" +#include "../sigsession.h" +#include "../device/devinst.h" +#include "../dialogs/fftoptions.h" + +#include namespace pv { namespace toolbars { -TrigBar::TrigBar(QWidget *parent) : +TrigBar::TrigBar(SigSession &session, QWidget *parent) : QToolBar("Trig Bar", parent), + _session(session), _enable(true), _trig_button(this), _protocol_button(this), _measure_button(this), - _search_button(this) + _search_button(this), + _math_button(this) { setMovable(false); + setContentsMargins(0,0,0,0); connect(&_trig_button, SIGNAL(clicked()), this, SLOT(trigger_clicked())); @@ -60,6 +68,8 @@ TrigBar::TrigBar(QWidget *parent) : _search_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/search-bar_cn.png"))); _search_button.setCheckable(true); + _math_button.setIcon(QIcon::fromTheme("trig", + QIcon(":/icons/math_cn.png"))); #else _trig_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/trigger.png"))); @@ -75,12 +85,29 @@ TrigBar::TrigBar(QWidget *parent) : _search_button.setIcon(QIcon::fromTheme("trig", QIcon(":/icons/search-bar.png"))); _search_button.setCheckable(true); + _math_button.setIcon(QIcon::fromTheme("trig", + QIcon(":/icons/math.png"))); #endif - addWidget(&_trig_button); - addWidget(&_protocol_button); - addWidget(&_measure_button); - addWidget(&_search_button); + _action_fft = new QAction(this); + _action_fft->setText(QApplication::translate( + "Math", "&FFT", 0)); + _action_fft->setIcon(QIcon::fromTheme("Math", + QIcon(":/icons/fft.png"))); + _action_fft->setObjectName(QString::fromUtf8("actionFft")); + connect(_action_fft, SIGNAL(triggered()), this, SLOT(on_actionFft_triggered())); + + _math_menu = new QMenu(this); + _math_menu->setContentsMargins(0,0,0,0); + _math_menu->addAction(_action_fft); + _math_button.setPopupMode(QToolButton::InstantPopup); + _math_button.setMenu(_math_menu); + + _trig_action = addWidget(&_trig_button); + _protocol_action = addWidget(&_protocol_button); + _measure_action = addWidget(&_measure_button); + _search_action = addWidget(&_search_button); + _math_action = addWidget(&_math_button); } void TrigBar::protocol_clicked() @@ -109,6 +136,7 @@ void TrigBar::enable_toggle(bool enable) _protocol_button.setDisabled(!enable); _measure_button.setDisabled(!enable); _search_button.setDisabled(!enable); + _math_button.setDisabled(!enable); #ifdef LANGUAGE_ZH_CN _trig_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/trigger_cn.png")) : @@ -119,6 +147,8 @@ void TrigBar::enable_toggle(bool enable) QIcon::fromTheme("trig", QIcon(":/icons/measure_dis_cn.png"))); _search_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/search-bar_cn.png")) : QIcon::fromTheme("trig", QIcon(":/icons/search-bar_dis_cn.png"))); + _math_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/math_cn.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/math_dis_cn.png"))); #else _trig_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/trigger.png")) : QIcon::fromTheme("trig", QIcon(":/icons/trigger_dis.png"))); @@ -128,6 +158,9 @@ void TrigBar::enable_toggle(bool enable) QIcon::fromTheme("trig", QIcon(":/icons/measure_dis.png"))); _search_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/search-bar.png")) : QIcon::fromTheme("trig", QIcon(":/icons/search-bar_dis.png"))); + _math_button.setIcon(enable ? QIcon::fromTheme("trig", QIcon(":/icons/math.png")) : + QIcon::fromTheme("trig", QIcon(":/icons/math_dis.png"))); + #endif } @@ -163,5 +196,36 @@ void TrigBar::close_all() } } +void TrigBar::reload() +{ + close_all(); + if (_session.get_device()->dev_inst()->mode == LOGIC) { + _trig_action->setVisible(true); + _protocol_action->setVisible(true); + _measure_action->setVisible(true); + _search_action->setVisible(true); + _math_action->setVisible(false); + } else if (_session.get_device()->dev_inst()->mode == ANALOG) { + _trig_action->setVisible(false); + _protocol_action->setVisible(false); + _measure_action->setVisible(true); + _search_action->setVisible(false); + _math_action->setVisible(false); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _trig_action->setVisible(true); + _protocol_action->setVisible(false); + _measure_action->setVisible(true); + _search_action->setVisible(false); + _math_action->setVisible(true); + } + update(); +} + +void TrigBar::on_actionFft_triggered() +{ + pv::dialogs::FftOptions fft_dlg(this, _session); + fft_dlg.exec(); +} + } // namespace toolbars } // namespace pv diff --git a/DSView/pv/toolbars/trigbar.h b/DSView/pv/toolbars/trigbar.h index 81e72ef2..7100799e 100644 --- a/DSView/pv/toolbars/trigbar.h +++ b/DSView/pv/toolbars/trigbar.h @@ -26,19 +26,25 @@ #include #include +#include +#include namespace pv { + +class SigSession; + namespace toolbars { class TrigBar : public QToolBar { Q_OBJECT public: - explicit TrigBar(QWidget *parent = 0); + explicit TrigBar(SigSession &session, QWidget *parent = 0); void enable_toggle(bool enable); void enable_protocol(bool enable); void close_all(); + void reload(); signals: void on_protocol(bool visible); @@ -52,12 +58,24 @@ public slots: void measure_clicked(); void search_clicked(); + void on_actionFft_triggered(); + private: + SigSession& _session; bool _enable; QToolButton _trig_button; QToolButton _protocol_button; QToolButton _measure_button; QToolButton _search_button; + QToolButton _math_button; + QAction* _trig_action; + QAction* _protocol_action; + QAction* _measure_action; + QAction* _search_action; + QAction* _math_action; + + QMenu* _math_menu; + QAction* _action_fft; }; diff --git a/DSView/pv/view/analogsignal.cpp b/DSView/pv/view/analogsignal.cpp index 595dff32..de501262 100644 --- a/DSView/pv/view/analogsignal.cpp +++ b/DSView/pv/view/analogsignal.cpp @@ -54,7 +54,7 @@ const float AnalogSignal::EnvelopeThreshold = 256.0f; AnalogSignal::AnalogSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, const sr_channel * const probe) : - Signal(dev_inst, probe, SR_CHANNEL_ANALOG), + Signal(dev_inst, probe), _data(data) { _colour = SignalColours[probe->index % countof(SignalColours)]; diff --git a/DSView/pv/view/decodetrace.cpp b/DSView/pv/view/decodetrace.cpp index bd076af5..b7117769 100644 --- a/DSView/pv/view/decodetrace.cpp +++ b/DSView/pv/view/decodetrace.cpp @@ -836,7 +836,7 @@ void DecodeTrace::on_new_decode_data() void DecodeTrace::on_decode_done() { if (_view) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->signals_changed(); } _session.decode_done(); diff --git a/DSView/pv/view/dsosignal.cpp b/DSView/pv/view/dsosignal.cpp index de5e0bbf..558ce007 100644 --- a/DSView/pv/view/dsosignal.cpp +++ b/DSView/pv/view/dsosignal.cpp @@ -24,6 +24,7 @@ #include +#include "../../extdef.h" #include "dsosignal.h" #include "pv/data/dso.h" #include "pv/data/dsosnapshot.h" @@ -106,13 +107,13 @@ const float DsoSignal::EnvelopeThreshold = 256.0f; const double DsoSignal::TrigMargin = 0.02; const int DsoSignal::UpMargin = 30; -const int DsoSignal::DownMargin = 30; +const int DsoSignal::DownMargin = 0; const int DsoSignal::RightMargin = 30; DsoSignal::DsoSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, const sr_channel * const probe): - Signal(dev_inst, probe, SR_CHANNEL_DSO), + Signal(dev_inst, probe), _data(data), _scale(0), _vDialActive(false), @@ -167,9 +168,14 @@ boost::shared_ptr DsoSignal::data() const return _data; } -void DsoSignal::set_view(pv::view::View *view) +boost::shared_ptr DsoSignal::dso_data() const { - Trace::set_view(view); + return _data; +} + +void DsoSignal::set_viewport(pv::view::Viewport *viewport) +{ + Trace::set_viewport(viewport); update_zeroPos(); const double ms_left = get_view_rect().right() - (MS_RectWidth + MS_RectMargin) * (get_index() + 1); @@ -257,7 +263,7 @@ bool DsoSignal::go_vDialPre() if (_view->session().get_capture_state() == SigSession::Stopped) _scale *= pre_vdiv/_vDial->get_value(); update_zeroPos(); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); return true; } else { @@ -276,7 +282,7 @@ bool DsoSignal::go_vDialNext() if (_view->session().get_capture_state() == SigSession::Stopped) _scale *= pre_vdiv/_vDial->get_value(); update_zeroPos(); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); return true; } else { @@ -507,7 +513,7 @@ bool DsoSignal::load_settings() _zero_off = _zeroPos * 255; if (_view) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); } return true; @@ -608,6 +614,11 @@ double DsoSignal::get_zeroRate() return _zeroPos; } +double DsoSignal::get_zeroValue() +{ + return _zero_off; +} + void DsoSignal::set_zeroPos(int pos) { if (enabled()) { @@ -644,7 +655,7 @@ void DsoSignal::set_factor(uint64_t factor) _dev_inst->set_config(_probe, NULL, SR_CONF_FACTOR, g_variant_new_uint64(factor)); _vDial->set_factor(factor); - _view->set_need_update(true); + _view->set_update(_viewport, true); _view->update(); } } @@ -668,7 +679,7 @@ uint64_t DsoSignal::get_factor() void DsoSignal::set_ms_show(bool show) { _ms_show = show; - _view->set_need_update(true); + _view->set_update(_viewport, true); } bool DsoSignal::get_ms_show() const @@ -731,10 +742,10 @@ void DsoSignal::update_zeroPos() QRectF DsoSignal::get_view_rect() const { - assert(_view); + assert(_viewport); return QRectF(0, UpMargin, - _view->viewport()->width() - RightMargin, - _view->viewport()->height() - UpMargin - DownMargin); + _viewport->width() - RightMargin, + _viewport->height() - UpMargin - DownMargin); } void DsoSignal::paint_back(QPainter &p, int left, int right) @@ -745,7 +756,9 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const int height = get_view_rect().height(); const int width = right - left; - p.setPen(Qt::NoPen); + QPen solidPen(Signal::dsFore); + solidPen.setStyle(Qt::SolidLine); + p.setPen(solidPen); p.setBrush(Trace::dsBack); p.drawRect(left, UpMargin, width, height); @@ -772,13 +785,14 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) p.setBrush(Trace::dsBlue); p.drawRect(shown_offset, UpMargin/2 - 3, shown_len, 6); - QPen pen(Signal::dsFore); - pen.setStyle(Qt::DotLine); - p.setPen(pen); + QPen dashPen(Signal::dsFore); + dashPen.setStyle(Qt::DashLine); + p.setPen(dashPen); const double spanY =height * 1.0 / DS_CONF_DSO_VDIVS; for (i = 1; i <= DS_CONF_DSO_VDIVS; i++) { const double posY = spanY * i + UpMargin; - p.drawLine(left, posY, right, posY); + if (i != DS_CONF_DSO_VDIVS) + p.drawLine(left, posY, right, posY); const double miniSpanY = spanY / 5; for (j = 1; j < 5; j++) { p.drawLine(width / 2.0f - 5, posY - miniSpanY * j, @@ -788,8 +802,8 @@ void DsoSignal::paint_back(QPainter &p, int left, int right) const double spanX = width * 1.0 / DS_CONF_DSO_HDIVS; for (i = 1; i <= DS_CONF_DSO_HDIVS; i++) { const double posX = spanX * i; - p.drawLine(posX, UpMargin, - posX, height + UpMargin); + if (i != DS_CONF_DSO_HDIVS) + p.drawLine(posX, UpMargin,posX, height + UpMargin); const double miniSpanX = spanX / 5; for (j = 1; j < 5; j++) { p.drawLine(posX - miniSpanX * j, height / 2.0f + UpMargin - 5, @@ -954,7 +968,7 @@ void DsoSignal::paint_trace(QPainter &p, } p.drawPolyline(points, point - points); - p.eraseRect(get_view_rect().right(), get_view_rect().top(), + p.eraseRect(get_view_rect().right()+1, get_view_rect().top(), _view->viewport()->width() - get_view_rect().width(), get_view_rect().height()); //delete[] samples; @@ -1095,7 +1109,7 @@ bool DsoSignal::mouse_press(int right, const QPoint pt) { int y = get_y(); bool setted = false; - const vector< boost::shared_ptr > traces(_view->get_traces()); + const vector< boost::shared_ptr > traces(_view->get_traces(ALL_VIEW)); const QRectF vDec_rect = get_rect(DSO_VDEC, y, right); const QRectF vInc_rect = get_rect(DSO_VINC, y, right); const QRectF hDec_rect = get_rect(DSO_HDEC, y, right); @@ -1156,7 +1170,7 @@ bool DsoSignal::mouse_wheel(int right, const QPoint pt, const int shift) { int y = get_y(); const vector< boost::shared_ptr > traces( - _view->get_traces()); + _view->get_traces(ALL_VIEW)); bool setted = false; const QRectF vDial_rect = get_rect(DSO_VDIAL, y, right); const QRectF hDial_rect = get_rect(DSO_HDIAL, y, right); @@ -1363,7 +1377,7 @@ void DsoSignal::paint_measure(QPainter &p) bool setted = false; if (_autoH) { - const vector< boost::shared_ptr > traces(_view->get_traces()); + const vector< boost::shared_ptr > traces(_view->get_traces(ALL_VIEW)); const double upPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.8; const double dnPeriod = get_hDialValue() * DS_CONF_DSO_HDIVS * 0.2; if (_period > upPeriod) { @@ -1404,18 +1418,18 @@ bool DsoSignal::measure(const QPointF &p) { if (_ms_gear_rect.contains(QPoint(p.x(), p.y()))) { _ms_gear_hover = true; - _view->set_need_update(true); + _view->set_update(_viewport, true); return false; } else if (_ms_gear_hover) { - _view->set_need_update(true); + _view->set_update(_viewport, true); _ms_gear_hover = false; } if (_ms_show_rect.contains(QPoint(p.x(), p.y()))) { _ms_show_hover = true; - _view->set_need_update(true); + _view->set_update(_viewport, true); return false; } else if (_ms_show_hover){ - _view->set_need_update(true); + _view->set_update(_viewport, true); _ms_show_hover = false; } diff --git a/DSView/pv/view/dsosignal.h b/DSView/pv/view/dsosignal.h index a2669d8a..032287e6 100644 --- a/DSView/pv/view/dsosignal.h +++ b/DSView/pv/view/dsosignal.h @@ -105,7 +105,8 @@ public: virtual ~DsoSignal(); boost::shared_ptr data() const; - void set_view(pv::view::View *view); + boost::shared_ptr dso_data() const; + void set_viewport(pv::view::Viewport *viewport); void set_scale(float scale); float get_scale(); @@ -154,6 +155,7 @@ public: */ int get_zeroPos(); double get_zeroRate(); + double get_zeroValue(); /** * Sets the mid-Y position of this signal. */ diff --git a/DSView/pv/view/header.cpp b/DSView/pv/view/header.cpp index ca38299f..7ccb9828 100644 --- a/DSView/pv/view/header.cpp +++ b/DSView/pv/view/header.cpp @@ -24,6 +24,7 @@ #include "header.h" #include "view.h" +#include "../../extdef.h" #include "trace.h" #include "dsosignal.h" #include "logicsignal.h" @@ -95,7 +96,7 @@ boost::shared_ptr Header::get_mTrace( { const int w = width(); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); BOOST_FOREACH(const boost::shared_ptr t, traces) { @@ -120,7 +121,7 @@ void Header::paintEvent(QPaintEvent*) const int w = width(); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); const bool dragging = !_drag_traces.empty(); BOOST_FOREACH(const boost::shared_ptr t, traces) @@ -137,7 +138,7 @@ void Header::mouseDoubleClickEvent(QMouseEvent *event) assert(event); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); if (event->button() & Qt::LeftButton) { _mouse_down_point = event->pos(); @@ -161,7 +162,7 @@ void Header::mousePressEvent(QMouseEvent *event) assert(event); const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); int action; const bool instant = _view.session().get_instant(); if (instant && _view.session().get_capture_state() == SigSession::Running) @@ -229,7 +230,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) if (action == Trace::COLOR && _colorFlag) { _context_trace = mTrace; changeColor(event); - _view.set_need_update(true); + _view.set_all_update(true); } else if (action == Trace::NAME && _nameFlag) { _context_trace = mTrace; changeName(event); @@ -238,7 +239,7 @@ void Header::mouseReleaseEvent(QMouseEvent *event) if (_moveFlag) { //move(event); _view.signals_changed(); - _view.set_need_update(true); + _view.set_all_update(true); } _colorFlag = false; _nameFlag = false; @@ -253,7 +254,7 @@ void Header::wheelEvent(QWheelEvent *event) if (event->orientation() == Qt::Vertical) { const vector< boost::shared_ptr > traces( - _view.get_traces()); + _view.get_traces(ALL_VIEW)); // Vertical scrolling double shift = event->delta() / 20.0; BOOST_FOREACH(const boost::shared_ptr t, traces) diff --git a/DSView/pv/view/logicsignal.cpp b/DSView/pv/view/logicsignal.cpp index 00df932b..94e96d7b 100644 --- a/DSView/pv/view/logicsignal.cpp +++ b/DSView/pv/view/logicsignal.cpp @@ -52,7 +52,7 @@ const int LogicSignal::StateRound = 5; LogicSignal::LogicSignal(boost::shared_ptr dev_inst, boost::shared_ptr data, const sr_channel * const probe) : - Signal(dev_inst, probe, SR_CHANNEL_LOGIC), + Signal(dev_inst, probe), _data(data), _trig(NONTRIG) { diff --git a/DSView/pv/view/mathtrace.cpp b/DSView/pv/view/mathtrace.cpp index 7aca389c..d8bb16c2 100644 --- a/DSView/pv/view/mathtrace.cpp +++ b/DSView/pv/view/mathtrace.cpp @@ -1,7 +1,488 @@ -#include "ffttrace.h" +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include +#include "mathtrace.h" -FftTrace::FftTrace() +#include +#include + +#include +#include + +#include "../sigsession.h" +#include "../data/dso.h" +#include "../data/dsosnapshot.h" +#include "../view/dsosignal.h" +#include "../view/viewport.h" +#include "../device/devinst.h" + +#include "../data/mathstack.h" + +using namespace boost; +using namespace std; + +namespace pv { +namespace view { + +const int MathTrace::UpMargin = 0; +const int MathTrace::DownMargin = 0; +const int MathTrace::RightMargin = 30; +const QString MathTrace::FFT_ViewMode[2] = { + "Linear RMS", + "DBV RMS" +}; + +const QString MathTrace::FreqPrefixes[9] = + {"", "", "", "", "K", "M", "G", "T", "P"}; +const int MathTrace::FirstSIPrefixPower = -9; +const int MathTrace::LastSIPrefixPower = 15; +const int MathTrace::Pricision = 2; +const int MathTrace::FreqMinorDivNum = 10; +const int MathTrace::TickHeight = 15; +const int MathTrace::VolDivNum = 5; + +const int MathTrace::DbvRanges[4] = { + 100, + 120, + 150, + 200, +}; + +const int MathTrace::HoverPointSize = 3; +const double MathTrace::VerticalRate = 1.0 / 2000.0; + +MathTrace::MathTrace(pv::SigSession &session, + boost::shared_ptr math_stack, int index) : + Trace("FFT("+QString::number(index)+")", index, SR_CHANNEL_FFT), + _session(session), + _math_stack(math_stack), + _enable(false), + _view_mode(0), + _hover_en(false), + _scale(1), + _offset(0) +{ + const vector< boost::shared_ptr > sigs(_session.get_signals()); + for(size_t i = 0; i < sigs.size(); i++) { + const boost::shared_ptr s(sigs[i]); + assert(s); + if (dynamic_pointer_cast(s) && index == s->get_index()) + _colour = s->get_colour(); + } +} + +MathTrace::~MathTrace() { } +bool MathTrace::enabled() const +{ + return _enable; +} + +void MathTrace::set_enable(bool enable) +{ + _enable = enable; +} + +int MathTrace::view_mode() const +{ + return _view_mode; +} + +void MathTrace::set_view_mode(int mode) +{ + assert(mode < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0])); + _view_mode = mode; +} + +std::vector MathTrace::get_view_modes_support() +{ + std::vector modes; + for (int i = 0; i < sizeof(FFT_ViewMode)/sizeof(FFT_ViewMode[0]); i++) { + modes.push_back(FFT_ViewMode[i]); + } + return modes; +} + +const boost::shared_ptr& MathTrace::get_math_stack() const +{ + return _math_stack; +} + +void MathTrace::init_zoom() +{ + _scale = 1; + _offset = 0; +} + +void MathTrace::zoom(double steps, int offset) +{ + if (!_view) + return; + + const int width = get_view_rect().width(); + double pre_offset = _offset + _scale*offset/width; + _scale *= std::pow(3.0/2.0, -steps); + _scale = max(min(_scale, 1.0), 100.0/_math_stack->get_sample_num()); + _offset = pre_offset - _scale*offset/width; + _offset = max(min(_offset, 1-_scale), 0.0); + + _view->set_update(_viewport, true); + _view->update(); +} + +void MathTrace::set_offset(double delta) +{ + int width = get_view_rect().width(); + _offset = _offset + (delta*_scale / width); + _offset = max(min(_offset, 1-_scale), 0.0); + + _view->set_update(_viewport, true); + _view->update(); +} + +double MathTrace::get_offset() const +{ + return _offset; +} + +void MathTrace::set_scale(double scale) +{ + _scale = max(min(scale, 1.0), 100.0/_math_stack->get_sample_num()); + + _view->set_update(_viewport, true); + _view->update(); +} + +double MathTrace::get_scale() const +{ + return _scale; +} + +void MathTrace::set_dbv_range(int range) +{ + _dbv_range = range; +} + +int MathTrace::dbv_range() const +{ + return _dbv_range; +} + +std::vector MathTrace::get_dbv_ranges() +{ + std::vector range; + for (int i = 0; i < sizeof(DbvRanges)/sizeof(DbvRanges[0]); i++) { + range.push_back(DbvRanges[i]); + } + return range; +} + +QString MathTrace::format_freq(double freq, unsigned precision) +{ + if (freq <= 0) { + return "0Hz"; + } else { + const int order = floor(log10f(freq)); + assert(order >= FirstSIPrefixPower); + assert(order <= LastSIPrefixPower); + const int prefix = floor((order - FirstSIPrefixPower)/ 3.0f); + const double divider = pow(10.0, max(prefix * 3.0 + FirstSIPrefixPower, 0.0)); + + QString s; + QTextStream ts(&s); + ts.setRealNumberPrecision(precision); + ts << fixed << freq / divider << + FreqPrefixes[prefix] << "Hz"; + return s; + } +} + +bool MathTrace::measure(const QPointF &p) +{ + _hover_en = false; + if(!_view || !enabled()) + return false; + + const QRectF window = get_view_rect(); + if (!window.contains(p)) + return false; + + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return false; + + const int full_size = (_math_stack->get_sample_num()/2+1); + const double view_off = full_size * _offset; + const int view_size = full_size*_scale; + const double sample_per_pixels = view_size/window.width(); + _hover_index = std::round(p.x() * sample_per_pixels + view_off); + + if (_hover_index < full_size) + _hover_en = true; + + //_view->set_update(_viewport, true); + _view->update(); + return true; +} + + +void MathTrace::paint_back(QPainter &p, int left, int right) +{ + if(!_view) + return; + + int i, j; + const int height = get_view_rect().height(); + const int width = right - left; + + QPen solidPen(Signal::dsFore); + solidPen.setStyle(Qt::SolidLine); + p.setPen(solidPen); + p.setBrush(Trace::dsBack); + p.drawRect(left, UpMargin, width, height); +} + +void MathTrace::paint_mid(QPainter &p, int left, int right) +{ + if(!_view) + return; + assert(right >= left); + + if (enabled()) { + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return; + + QColor trace_colour = _colour; + trace_colour.setAlpha(150); + p.setPen(trace_colour); + + const int full_size = (_math_stack->get_sample_num()/2+1); + const double view_off = full_size * _offset; + const int view_start = floor(view_off); + const int view_size = full_size*_scale; + QPointF *points = new QPointF[samples.size()]; + QPointF *point = points; + + const bool dc_ignored = _math_stack->dc_ignored(); + const double height = get_view_rect().height(); + const double width = right - left; + const double pixels_per_sample = width/view_size; + + double vdiv; + double vfactor; + double voffset; + BOOST_FOREACH(const boost::shared_ptr s, _session.get_signals()) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if(dsoSig->get_index() == _math_stack->get_index()) { + vdiv = dsoSig->get_vDialValue(); + vfactor = dsoSig->get_factor(); + voffset = dsoSig->get_zeroRate(); + break; + } + } + } + if (_view_mode == 0) { + _vmin = 0; + _vmax = (vdiv*DS_CONF_DSO_HDIVS*vfactor)*VerticalRate; + } else { + _vmax = 20*log10((vdiv*DS_CONF_DSO_HDIVS*vfactor)*VerticalRate); + _vmin = _vmax - _dbv_range; + } + + //const double max_value = *std::max_element(dc_ignored ? ++samples.begin() : samples.begin(), samples.end()); + //const double min_value = *std::min_element(dc_ignored ? ++samples.begin() : samples.begin(), samples.end()); + //_vmax = (_view_mode == 0) ? max_value : 20*log10(max_value); + //_vmin = (_view_mode == 0) ? min_value : 20*log10(min_value); + const double scale = height / (_vmax - _vmin); + + double x = (view_start-view_off)*pixels_per_sample; + uint64_t sample = view_start; + if (dc_ignored && sample == 0) { + sample++; + x += pixels_per_sample; + } + double min_mag = pow(10.0, _vmin/20); + do{ + double mag = samples[sample]; + if (_view_mode != 0) { + if (mag < min_mag) + mag = _vmin; + else + mag = 20*log10(mag); + } + const double y = height - (scale * (mag - _vmin)); + *point++ = QPointF(x, y); + x += pixels_per_sample; + sample++; + }while(x= left); + + const int text_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, "8").height(); + const double width = get_view_rect().width(); + const double height = get_view_rect().height(); + double blank_top = 0; + double blank_right = width; + + // horizontal ruler + const double NyFreq = _session.get_device()->get_sample_rate() / (2.0 * _math_stack->get_sample_interval()); + const double deltaFreq = _session.get_device()->get_sample_rate() * 1.0 / + (_math_stack->get_sample_num() * _math_stack->get_sample_interval()); + const double FreqRange = NyFreq * _scale; + const double FreqOffset = NyFreq * _offset; + + const int order = (int)floor(log10(FreqRange)); + const double multiplier = (pow(10.0, order) == FreqRange) ? FreqRange/10 : pow(10.0, order); + const double freq_per_pixel = FreqRange / width; + + p.setPen(Trace::DARK_FORE); + p.setBrush(Qt::NoBrush); + double tick_freq = multiplier * (int)floor(FreqOffset / multiplier); + int division = (int)round(tick_freq * FreqMinorDivNum / multiplier); + double x = (tick_freq - FreqOffset) / freq_per_pixel; + do{ + if (division%FreqMinorDivNum == 0) { + QString freq_str = format_freq(tick_freq); + double typical_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, freq_str).width() + 10; + p.drawLine(x, 1, x, TickHeight); + if (x > typical_width/2 && (width-x) > typical_width/2) + p.drawText(x-typical_width/2, TickHeight, typical_width, text_height, + AlignCenter | AlignTop | TextDontClip, freq_str); + } else { + p.drawLine(x, 1, x, TickHeight/2); + } + tick_freq += multiplier/FreqMinorDivNum; + division++; + x = (tick_freq - FreqOffset) / freq_per_pixel; + } while(x < width); + blank_top = max(blank_top, (double)TickHeight + text_height); + + // delta Frequency + QString freq_str = QString::fromWCharArray(L" \u0394") + "Freq: " + format_freq(deltaFreq,4); + p.drawText(0, 0, width, get_view_rect().height(), + AlignRight | AlignBottom | TextDontClip, freq_str); + double delta_left = width-p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, freq_str).width(); + blank_right = min(delta_left, blank_right); + + // Vertical ruler + const double vRange = _vmax - _vmin; + const double vOffset = _vmin; + const double vol_per_tick = vRange / VolDivNum; + + p.setPen(Trace::DARK_FORE); + p.setBrush(Qt::NoBrush); + double tick_vol = vol_per_tick + vOffset; + double y = height - height / VolDivNum; + const QString unit = (_view_mode == 0) ? "" : "dbv"; + do{ + if (y > text_height && y < (height - text_height)) { + QString vol_str = QString::number(tick_vol, 'f', Pricision) + unit; + double vol_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, vol_str).width(); + p.drawLine(width, y, width-TickHeight/2, y); + p.drawText(width-TickHeight-vol_width, y-text_height/2, vol_width, text_height, + AlignCenter | AlignTop | TextDontClip, vol_str); + blank_right = min(width-TickHeight-vol_width, blank_right); + } + tick_vol += vol_per_tick; + y -= height / VolDivNum; + } while(y > 0); + + // Hover measure + if (_hover_en) { + const std::vector samples(_math_stack->get_fft_spectrum()); + if(samples.empty()) + return; + const int full_size = (_math_stack->get_sample_num()/2+1); + const double view_off = full_size * _offset; + const int view_size = full_size*_scale; + const double scale = height / (_vmax - _vmin); + const double pixels_per_sample = width/view_size; + double x = (_hover_index-view_off)*pixels_per_sample; + double min_mag = pow(10.0, _vmin/20); + _hover_value = samples[_hover_index]; + if (_view_mode != 0) { + if (_hover_value < min_mag) + _hover_value = _vmin; + else + _hover_value = 20*log10(_hover_value); + } + const double y = height - (scale * (_hover_value - _vmin)); + _hover_point = QPointF(x, y); + + p.setPen(QPen(Trace::DARK_FORE, 1, Qt::DashLine)); + p.setBrush(Qt::NoBrush); + p.drawLine(_hover_point.x(), 0, _hover_point.x(), height); + + QString hover_str = QString::number(_hover_value, 'f', 4) + unit + "@" + format_freq(deltaFreq * _hover_index, 4); + const int hover_width = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, hover_str).width(); + const int hover_height = p.boundingRect(0, 0, INT_MAX, INT_MAX, + AlignLeft | AlignTop, hover_str).height(); + QRectF hover_rect(_hover_point.x(), _hover_point.y()-hover_height, hover_width, hover_height); + if (hover_rect.right() > blank_right) + hover_rect.moveRight(min(_hover_point.x(), blank_right)); + if (hover_rect.top() < blank_top) + hover_rect.moveTop(max(_hover_point.y(), blank_top)); + if (hover_rect.top() > 0) + p.drawText(hover_rect, AlignCenter | AlignTop | TextDontClip, hover_str); + + p.setPen(Qt::NoPen); + p.setBrush(Trace::DARK_FORE); + p.drawEllipse(_hover_point, HoverPointSize, HoverPointSize); + } +} + +void MathTrace::paint_type_options(QPainter &p, int right, const QPoint pt) +{ + (void)p; + (void)pt; + (void)right; +} + +QRectF MathTrace::get_view_rect() const +{ + assert(_viewport); + return QRectF(0, UpMargin, + _viewport->width() - RightMargin, + _viewport->height() - UpMargin - DownMargin); +} + +} // namespace view +} // namespace pv diff --git a/DSView/pv/view/mathtrace.h b/DSView/pv/view/mathtrace.h index a64ede6a..7a39babb 100644 --- a/DSView/pv/view/mathtrace.h +++ b/DSView/pv/view/mathtrace.h @@ -1,11 +1,156 @@ -#ifndef FFTTRACE_H -#define FFTTRACE_H +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef DSVIEW_PV_VIEW_MATHTRACE_H +#define DSVIEW_PV_VIEW_MATHTRACE_H -class FftTrace +#include "trace.h" + +#include +#include + +#include + +struct srd_channel; + +namespace pv { + +class SigSession; + +namespace data{ +class MathStack; +} + +namespace view { + +class MathTrace : public Trace { + Q_OBJECT + +private: + static const int UpMargin; + static const int DownMargin; + static const int RightMargin; + static const QString FFT_ViewMode[2]; + + static const QString FreqPrefixes[9]; + static const int FirstSIPrefixPower; + static const int LastSIPrefixPower; + static const int Pricision; + static const int FreqMinorDivNum; + static const int TickHeight; + static const int VolDivNum; + + static const int DbvRanges[4]; + + static const int HoverPointSize; + + static const double VerticalRate; + public: - FftTrace(); + MathTrace(pv::SigSession &session, + boost::shared_ptr math_stack, int index); + ~MathTrace(); + + bool enabled() const; + void set_enable(bool enable); + + void init_zoom(); + void zoom(double steps, int offset); + bool zoom_hit() const; + void set_zoom_hit(bool hit); + + void set_offset(double delta); + double get_offset() const; + + void set_scale(double scale); + double get_scale() const; + + void set_dbv_range(int range); + int dbv_range() const; + std::vector get_dbv_ranges(); + + int view_mode() const; + void set_view_mode(int mode); + std::vector get_view_modes_support(); + + const boost::shared_ptr& get_math_stack() const; + + static QString format_freq(double freq, unsigned precision = Pricision); + + bool measure(const QPointF &p); + + /** + * Paints the background layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal. + * @param right the x-coordinate of the right edge of the signal. + **/ + void paint_back(QPainter &p, int left, int right); + + /** + * Paints the mid-layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_mid(QPainter &p, int left, int right); + + /** + * Paints the foreground layer of the trace with a QPainter + * @param p the QPainter to paint into. + * @param left the x-coordinate of the left edge of the signal + * @param right the x-coordinate of the right edge of the signal + **/ + void paint_fore(QPainter &p, int left, int right); + + QRectF get_view_rect() const; + +protected: + void paint_type_options(QPainter &p, int right, const QPoint pt); + +private: + +private slots: + +private: + pv::SigSession &_session; + boost::shared_ptr _math_stack; + + bool _enable; + int _view_mode; + + double _vmax; + double _vmin; + int _dbv_range; + + uint64_t _hover_index; + bool _hover_en; + QPointF _hover_point; + double _hover_value; + + double _scale; + double _offset; }; -#endif // FFTTRACE_H +} // namespace view +} // namespace pv + +#endif // DSVIEW_PV_VIEW_FFTTRACE_H diff --git a/DSView/pv/view/ruler.cpp b/DSView/pv/view/ruler.cpp index 3fdab4b9..1bbfb340 100644 --- a/DSView/pv/view/ruler.cpp +++ b/DSView/pv/view/ruler.cpp @@ -109,7 +109,7 @@ QString Ruler::format_freq(double period, unsigned precision) QString s; QTextStream ts(&s); ts.setRealNumberPrecision(precision); - ts << fixed << forcesign << 1 / (period * multiplier) << + ts << fixed << 1 / (period * multiplier) << FreqPrefixes[prefix] << "Hz"; return s; } diff --git a/DSView/pv/view/signal.cpp b/DSView/pv/view/signal.cpp index e4cba490..04a4e6ed 100644 --- a/DSView/pv/view/signal.cpp +++ b/DSView/pv/view/signal.cpp @@ -35,8 +35,8 @@ namespace pv { namespace view { Signal::Signal(boost::shared_ptr dev_inst, - const sr_channel *const probe, int type) : - Trace(probe->name, probe->index, type), + const sr_channel *const probe) : + Trace(probe->name, probe->index, probe->type), _dev_inst(dev_inst), _probe(probe) { diff --git a/DSView/pv/view/signal.h b/DSView/pv/view/signal.h index 3ad90f44..632f1e37 100644 --- a/DSView/pv/view/signal.h +++ b/DSView/pv/view/signal.h @@ -57,7 +57,7 @@ private: protected: Signal(boost::shared_ptr dev_inst, - const sr_channel * const probe, int type); + const sr_channel * const probe); /** * Copy constructor diff --git a/DSView/pv/view/trace.cpp b/DSView/pv/view/trace.cpp index 3c79bc1a..661f59f5 100644 --- a/DSView/pv/view/trace.cpp +++ b/DSView/pv/view/trace.cpp @@ -43,7 +43,7 @@ const QColor Trace::dsRed = QColor(213, 15, 37, 255); const QColor Trace::dsGreen = QColor(0, 153, 37, 200); const QColor Trace::dsGray = QColor(0x88, 0x8A, 0x85, 60); const QColor Trace::dsFore = QColor(0xff, 0xff, 0xff, 60); -const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 180); +const QColor Trace::dsBack = QColor(0x16, 0x18, 0x23, 200); const QColor Trace::dsDisable = QColor(0x88, 0x8A, 0x85, 200); const QColor Trace::dsActive = QColor(17, 133, 209, 255); const QColor Trace::dsLightBlue = QColor(17, 133, 209, 150); @@ -53,6 +53,7 @@ const QPen Trace::SignalAxisPen = QColor(128, 128, 128, 64); const QColor Trace::DARK_BACK = QColor(48, 47, 47, 255); const QColor Trace::DARK_FORE = QColor(150, 150, 150, 255); const QColor Trace::DARK_HIGHLIGHT = QColor(32, 32, 32, 255); +const QColor Trace::DARK_BLUE = QColor(17, 133, 209, 255); const QColor Trace::PROBE_COLORS[8] = { QColor(0x50, 0x50, 0x50), // Black @@ -187,7 +188,7 @@ void Trace::set_old_v_offset(int v_offset) int Trace::get_zeroPos() { - return _v_offset - _view->v_offset(); + return _v_offset; } int Trace::get_totalHeight() const @@ -211,6 +212,17 @@ pv::view::View* Trace::get_view() const return _view; } +void Trace::set_viewport(pv::view::Viewport *viewport) +{ + assert(viewport); + _viewport = viewport; +} + +pv::view::Viewport* Trace::get_viewport() const +{ + return _viewport; +} + void Trace::paint_back(QPainter &p, int left, int right) { QPen pen(Signal::dsGray); @@ -236,6 +248,9 @@ void Trace::paint_fore(QPainter &p, int left, int right) void Trace::paint_label(QPainter &p, int right, const QPoint pt) { + if (_type == SR_CHANNEL_FFT && !enabled()) + return; + compute_text_size(p); const int y = get_y(); @@ -267,7 +282,7 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) }; p.setPen(Qt::transparent); - if (_type == SR_CHANNEL_DSO) { + if (_type == SR_CHANNEL_DSO || _type == SR_CHANNEL_FFT) { p.setBrush((label_rect.contains(pt) || selected()) ? _colour.darker() : _colour); p.drawPolygon(points, countof(points)); } else { @@ -284,6 +299,8 @@ void Trace::paint_label(QPainter &p, int right, const QPoint pt) p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "A"); else if (_type == SR_CHANNEL_DECODER) p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "D"); + else if (_type == SR_CHANNEL_FFT) + p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, "M"); else p.drawText(label_rect, Qt::AlignCenter | Qt::AlignVCenter, QString::number(_index_list.front())); } @@ -355,7 +372,7 @@ QRectF Trace::get_view_rect() const int Trace::get_y() const { - return _v_offset - _view->v_offset(); + return _v_offset; } QColor Trace::get_text_colour() const diff --git a/DSView/pv/view/trace.h b/DSView/pv/view/trace.h index 26d9b504..1c30de77 100644 --- a/DSView/pv/view/trace.h +++ b/DSView/pv/view/trace.h @@ -31,6 +31,8 @@ #include +#include + #include "selectableitem.h" #include "dsldial.h" @@ -40,6 +42,7 @@ namespace pv { namespace view { class View; +class Viewport; class Trace : public SelectableItem { @@ -73,6 +76,7 @@ public: static const QColor DARK_BACK; static const QColor DARK_FORE; static const QColor DARK_HIGHLIGHT; + static const QColor DARK_BLUE; static const QColor PROBE_COLORS[8]; @@ -166,6 +170,8 @@ public: virtual void set_view(pv::view::View *view); pv::view::View* get_view() const; + virtual void set_viewport(pv::view::Viewport *viewport); + pv::view::Viewport* get_viewport() const; /** * Paints the background layer of the trace with a QPainter @@ -290,6 +296,7 @@ signals: protected: pv::view::View *_view; + pv::view::Viewport *_viewport; QString _name; QColor _colour; diff --git a/DSView/pv/view/view.cpp b/DSView/pv/view/view.cpp index df0e2e87..43cf5868 100644 --- a/DSView/pv/view/view.cpp +++ b/DSView/pv/view/view.cpp @@ -41,6 +41,7 @@ #include "dsosignal.h" #include "view.h" #include "viewport.h" +#include "mathtrace.h" #include "../device/devinst.h" #include "pv/sigsession.h" @@ -68,25 +69,19 @@ const QColor View::CursorAreaColour(220, 231, 243); const QSizeF View::LabelPadding(4, 4); View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget *parent) : - QAbstractScrollArea(parent), + QScrollArea(parent), _session(session), _sampling_bar(sampling_bar), - _viewport(new Viewport(*this)), - _ruler(new Ruler(*this)), - _header(new Header(*this)), - _devmode(new DevMode(this, session)), _scale(1e-8), _preScale(1e-6), _maxscale(1e9), _minscale(1e-15), _offset(0), _preOffset(0), - _v_offset(0), _updating_scroll(false), - _need_update(false), _show_cursors(false), _trig_pos(0), - _hover_point(-1, -1) + _hover_point(-1, -1) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); @@ -95,8 +90,60 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(v_scroll_value_changed(int))); + // trace viewport map + _trace_view_map[SR_CHANNEL_LOGIC] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_GROUP] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_DECODER] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_ANALOG] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_DSO] = TIME_VIEW; + _trace_view_map[SR_CHANNEL_FFT] = FFT_VIEW; + + _active_viewport = NULL; + _ruler = new Ruler(*this); + _header = new Header(*this); + _devmode = new DevMode(this, session); + setViewportMargins(headerWidth(), RulerHeight, 0, 0); - setViewport(_viewport); + //setViewport(_viewport); + + // windows splitter + _time_viewport = new Viewport(*this, TIME_VIEW); + _time_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _time_viewport->setMinimumHeight(100); + connect(_time_viewport, SIGNAL(measure_updated()), + this, SLOT(on_measure_updated())); + _fft_viewport = new Viewport(*this, FFT_VIEW); + _fft_viewport->setVisible(false); + _fft_viewport->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + _fft_viewport->setMinimumHeight(100); + connect(_fft_viewport, SIGNAL(measure_updated()), + this, SLOT(on_measure_updated())); + + _vsplitter = new QSplitter(this); + _vsplitter->setOrientation(Qt::Vertical); + _vsplitter->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + + _viewport_list.push_back(_time_viewport); + _vsplitter->addWidget(_time_viewport); + _vsplitter->setCollapsible(0, false); + _vsplitter->setStretchFactor(0, 2); + _viewport_list.push_back(_fft_viewport); + _vsplitter->addWidget(_fft_viewport); + _vsplitter->setCollapsible(1, false); + _vsplitter->setStretchFactor(1, 1); + + _viewcenter = new QWidget(this); + _viewcenter->setContentsMargins(0,0,0,0); + QGridLayout* layout = new QGridLayout(_viewcenter); + layout->setContentsMargins(0,0,0,0); + _viewcenter->setLayout(layout); + layout->addWidget(_vsplitter, 0, 0); + QWidget* bottom = new QWidget(this); + bottom->setFixedHeight(10); + layout->addWidget(bottom, 1, 0); + setViewport(_viewcenter); + connect(_vsplitter, SIGNAL(splitterMoved(int,int)), + this, SLOT(splitterMoved(int, int))); connect(&_session, SIGNAL(device_setted()), _devmode, SLOT(set_device())); @@ -117,12 +164,13 @@ View::View(SigSession &session, pv::toolbars::SamplingBar *sampling_bar, QWidget connect(_header, SIGNAL(header_updated()), this, SLOT(header_updated())); - _viewport->installEventFilter(this); + _time_viewport->installEventFilter(this); + _fft_viewport->installEventFilter(this); _ruler->installEventFilter(this); _header->installEventFilter(this); _devmode->installEventFilter(this); - _viewport->setObjectName(tr("ViewArea_viewport")); + _viewcenter->setObjectName(tr("ViewArea_center")); _ruler->setObjectName(tr("ViewArea_ruler")); _header->setObjectName(tr("ViewArea_header")); @@ -148,11 +196,6 @@ double View::offset() const return _offset; } -int View::v_offset() const -{ - return _v_offset; -} - double View::get_minscale() const { return _minscale; @@ -168,14 +211,15 @@ void View::zoom(double steps) zoom(steps, get_view_width() / 2); } -void View::set_need_update(bool need_update) +void View::set_update(Viewport *viewport, bool need_update) { - _need_update = need_update; + viewport->set_need_update(need_update); } -bool View::need_update() const +void View::set_all_update(bool need_update) { - return _need_update; + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->set_need_update(need_update); } void View::update_sample(bool instant) @@ -235,7 +279,7 @@ void View::zoom(double steps, int offset) if (_scale != _preScale || _offset != _preOffset) { _header->update(); _ruler->update(); - _viewport->update(); + viewport_update(); update_scroll(); } //} @@ -255,7 +299,7 @@ void View::set_scale_offset(double scale, double offset) update_scroll(); _header->update(); _ruler->update(); - _viewport->update(); + viewport_update(); } //} } @@ -269,25 +313,57 @@ void View::set_preScale_preOffset() set_scale_offset(_preScale, _preOffset); } -vector< boost::shared_ptr > View::get_traces() const +vector< boost::shared_ptr > View::get_traces(int type) { +// const vector< boost::shared_ptr > sigs(_session.get_signals()); +// const vector< boost::shared_ptr > groups(_session.get_group_signals()); +//#ifdef ENABLE_DECODE +// const vector< boost::shared_ptr > decode_sigs( +// _session.get_decode_signals()); +// vector< boost::shared_ptr > traces( +// sigs.size() + groups.size() + decode_sigs.size()); +//#else +// vector< boost::shared_ptr > traces(sigs.size() + groups.size()); +//#endif + +// vector< boost::shared_ptr >::iterator i = traces.begin(); +// i = copy(sigs.begin(), sigs.end(), i); +//#ifdef ENABLE_DECODE +// i = copy(decode_sigs.begin(), decode_sigs.end(), i); +//#endif +// i = copy(groups.begin(), groups.end(), i); + +// stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets); +// return traces; + const vector< boost::shared_ptr > sigs(_session.get_signals()); const vector< boost::shared_ptr > groups(_session.get_group_signals()); #ifdef ENABLE_DECODE const vector< boost::shared_ptr > decode_sigs( _session.get_decode_signals()); - vector< boost::shared_ptr > traces( - sigs.size() + groups.size() + decode_sigs.size()); -#else - vector< boost::shared_ptr > traces(sigs.size() + groups.size()); #endif + const vector< boost::shared_ptr > maths(_session.get_math_signals()); - vector< boost::shared_ptr >::iterator i = traces.begin(); - i = copy(sigs.begin(), sigs.end(), i); + vector< boost::shared_ptr > traces; + BOOST_FOREACH(boost::shared_ptr t, sigs) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } #ifdef ENABLE_DECODE - i = copy(decode_sigs.begin(), decode_sigs.end(), i); + BOOST_FOREACH(boost::shared_ptr t, decode_sigs) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } #endif - i = copy(groups.begin(), groups.end(), i); + BOOST_FOREACH(boost::shared_ptr t, groups) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } + + BOOST_FOREACH(boost::shared_ptr t, maths) { + if (type == ALL_VIEW || _trace_view_map[t->get_type()] == type) + traces.push_back(t); + } stable_sort(traces.begin(), traces.end(), compare_trace_v_offsets); return traces; @@ -323,21 +399,21 @@ void View::show_cursors(bool show) { _show_cursors = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::show_trig_cursor(bool show) { _show_trig_cursor = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::show_search_cursor(bool show) { _show_search_cursor = show; _ruler->update(); - _viewport->update(); + viewport_update(); } void View::set_trig_pos(quint64 trig_pos) @@ -353,7 +429,7 @@ void View::set_trig_pos(quint64 trig_pos) _trigger_time = _trigger_time.addSecs(secs); _ruler->update(); - _viewport->update(); + viewport_update(); } void View::set_search_pos(uint64_t search_pos) @@ -365,7 +441,7 @@ void View::set_search_pos(uint64_t search_pos) _search_cursor->set_index(search_pos); set_scale_offset(_scale, time - _scale * get_view_width() / 2); _ruler->update(); - _viewport->update(); + viewport_update(); } uint64_t View::get_trig_pos() @@ -385,7 +461,7 @@ const QPointF& View::hover_point() const void View::normalize_layout() { - const vector< boost::shared_ptr > traces(get_traces()); + const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); int v_min = INT_MAX; BOOST_FOREACH(const boost::shared_ptr t, traces) @@ -395,7 +471,7 @@ void View::normalize_layout() BOOST_FOREACH(boost::shared_ptr t, traces) t->set_v_offset(t->get_v_offset() + delta); - verticalScrollBar()->setSliderPosition(_v_offset + delta); + verticalScrollBar()->setSliderPosition(delta); v_scroll_value_changed(verticalScrollBar()->sliderPosition()); } @@ -422,9 +498,9 @@ void View::get_scroll_layout(double &length, double &offset) const void View::update_scroll() { - assert(_viewport); + assert(_viewcenter); - const QSize areaSize = _viewport->size(); + const QSize areaSize = _viewcenter->size(); // Set the horizontal scroll bar double length = 0, offset = 0; @@ -448,8 +524,7 @@ void View::update_scroll() // Set the vertical scrollbar verticalScrollBar()->setPageStep(areaSize.height()); - verticalScrollBar()->setRange(0, - _viewport->get_total_height() - areaSize.height()); + verticalScrollBar()->setRange(0,0); } void View::update_scale() @@ -473,47 +548,93 @@ void View::update_scale() _trig_cursor->set_index(_trig_pos); _ruler->update(); - _viewport->update(); + viewport_update(); } void View::signals_changed() { int total_rows = 0; uint8_t max_height = MaxHeightUnit; - const vector< boost::shared_ptr > traces(get_traces()); - BOOST_FOREACH(const boost::shared_ptr t, traces) - { - assert(t); - if (dynamic_pointer_cast(t) || - t->enabled()) - total_rows += t->rows_size(); + vector< boost::shared_ptr > time_traces; + vector< boost::shared_ptr > fft_traces; + BOOST_FOREACH(const boost::shared_ptr t, get_traces(ALL_VIEW)) { + if (_trace_view_map[t->get_type()] == TIME_VIEW) + time_traces.push_back(t); + else if (_trace_view_map[t->get_type()] == FFT_VIEW) + if (t->enabled()) + fft_traces.push_back(t); } - const double height = (_viewport->height() - - horizontalScrollBar()->height() - - 2 * SignalMargin * traces.size()) * 1.0 / total_rows; - - if (_session.get_device()->dev_inst()->mode == LOGIC) { - GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); - if (gvar != NULL) { - max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; - g_variant_unref(gvar); + if (!fft_traces.empty()) { + if (!_fft_viewport->isVisible()) { + _fft_viewport->setVisible(true); + _fft_viewport->clear_measure(); + _viewport_list.push_back(_fft_viewport); + _vsplitter->refresh(); + } + BOOST_FOREACH(boost::shared_ptr t, fft_traces) { + t->set_view(this); + t->set_viewport(_fft_viewport); + t->set_totalHeight(_fft_viewport->height()); + t->set_v_offset(_fft_viewport->geometry().bottom()); } - _signalHeight = (int)((height <= 0) ? 1 : (height >= max_height) ? max_height : height); } else { - _signalHeight = (int)((height <= 0) ? 1 : height); - } - _spanY = _signalHeight + 2 * SignalMargin; - int next_v_offset = SignalMargin; - BOOST_FOREACH(boost::shared_ptr t, traces) { - t->set_view(this); - const double traceHeight = _signalHeight*t->rows_size(); - t->set_totalHeight((int)traceHeight); - t->set_v_offset(next_v_offset + 0.5 * traceHeight + SignalMargin); - next_v_offset += traceHeight + 2 * SignalMargin; - } + _fft_viewport->setVisible(false); + _vsplitter->refresh(); + + // Find the decoder in the stack + std::list< Viewport *>::iterator iter = _viewport_list.begin(); + for(int i = 0; i < _viewport_list.size(); i++, iter++) + if ((*iter) == _fft_viewport) + break; + // Delete the element + if (iter != _viewport_list.end()) + _viewport_list.erase(iter); + } + + if (!time_traces.empty() && _time_viewport) { + BOOST_FOREACH(const boost::shared_ptr t, time_traces) { + assert(t); + if (dynamic_pointer_cast(t) || + t->enabled()) + total_rows += t->rows_size(); + } + + const double height = (_time_viewport->height() + - horizontalScrollBar()->height() + - 2 * SignalMargin * time_traces.size()) * 1.0 / total_rows; + + if (_session.get_device()->dev_inst()->mode == LOGIC) { + GVariant* gvar = _session.get_device()->get_config(NULL, NULL, SR_CONF_MAX_HEIGHT_VALUE); + if (gvar != NULL) { + max_height = (g_variant_get_byte(gvar) + 1) * MaxHeightUnit; + g_variant_unref(gvar); + } + _signalHeight = (int)((height <= 0) ? 1 : (height >= max_height) ? max_height : height); + } else if (_session.get_device()->dev_inst()->mode == DSO) { + _signalHeight = (_header->height() + - horizontalScrollBar()->height() + - 2 * SignalMargin * time_traces.size()) * 1.0 / total_rows; + } else { + _signalHeight = (int)((height <= 0) ? 1 : height); + } + _spanY = _signalHeight + 2 * SignalMargin; + int next_v_offset = SignalMargin; + BOOST_FOREACH(boost::shared_ptr t, time_traces) { + t->set_view(this); + t->set_viewport(_time_viewport); + const double traceHeight = _signalHeight*t->rows_size(); + t->set_totalHeight((int)traceHeight); + t->set_v_offset(next_v_offset + 0.5 * traceHeight + SignalMargin); + next_v_offset += traceHeight + 2 * SignalMargin; + + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(t)) + dsoSig->set_scale(dsoSig->get_view_rect().height() / 256.0f); + } + _time_viewport->clear_measure(); + } - _viewport->clear_measure(); header_updated(); normalize_layout(); data_updated(); @@ -525,7 +646,7 @@ bool View::eventFilter(QObject *object, QEvent *event) if (type == QEvent::MouseMove) { const QMouseEvent *const mouse_event = (QMouseEvent*)event; - if (object == _ruler || object == _viewport) { + if (object == _ruler || object == _time_viewport || object == _fft_viewport) { //_hover_point = QPoint(mouse_event->x(), 0); double cur_periods = (mouse_event->pos().x() * _scale + _offset) / _ruler->get_min_period(); double integer_x = (round(cur_periods) * _ruler->get_min_period() - _offset ) / _scale; @@ -575,7 +696,7 @@ int View::headerWidth() QFont font = QApplication::font(); QFontMetrics fm(font); - const vector< boost::shared_ptr > traces(get_traces()); + const vector< boost::shared_ptr > traces(get_traces(ALL_VIEW)); if (!traces.empty()){ BOOST_FOREACH(const boost::shared_ptr t, traces) { maxNameWidth = max(fm.boundingRect(t->get_name()).width(), maxNameWidth); @@ -593,8 +714,10 @@ int View::headerWidth() void View::resizeEvent(QResizeEvent*) { + setViewportMargins(headerWidth(), RulerHeight, 0, 0); update_margins(); update_scroll(); + signals_changed(); if (_session.get_device()->dev_inst()->mode == DSO) _scale = _session.get_device()->get_time_base() * std::pow(10.0, -9.0) * DS_CONF_DSO_HDIVS / get_view_width(); @@ -605,10 +728,10 @@ void View::resizeEvent(QResizeEvent*) _scale = min(_scale, _maxscale); - signals_changed(); _ruler->update(); _header->header_resize(); - _need_update = true; + set_update(_time_viewport, true); + set_update(_fft_viewport, true); } void View::h_scroll_value_changed(int value) @@ -631,15 +754,14 @@ void View::h_scroll_value_changed(int value) if (_offset != _preOffset) { _ruler->update(); - _viewport->update(); + viewport_update(); } } void View::v_scroll_value_changed(int value) { - _v_offset = value; _header->update(); - _viewport->update(); + viewport_update(); } void View::data_updated() @@ -651,18 +773,19 @@ void View::data_updated() update_scroll(); // Repaint the view - _need_update = true; - _viewport->update(); + set_update(_time_viewport, true); + set_update(_fft_viewport, true); + viewport_update(); } void View::update_margins() { - _ruler->setGeometry(_viewport->x(), 0, - get_view_width(), _viewport->y()); - _header->setGeometry(0, _viewport->y(), - _viewport->x(), _viewport->height()); + _ruler->setGeometry(_viewcenter->x(), 0, + get_view_width(), _viewcenter->y()); + _header->setGeometry(0, _viewcenter->y(), + _viewcenter->x(), _viewcenter->height()); _devmode->setGeometry(0, 0, - _viewport->x(), _viewport->y()); + _viewcenter->x(), _viewcenter->y()); } void View::header_updated() @@ -673,21 +796,21 @@ void View::header_updated() // Update the scroll bars update_scroll(); - _viewport->update(); + viewport_update(); _header->update(); } void View::marker_time_changed() { _ruler->update(); - _viewport->update(); + viewport_update(); } void View::on_traces_moved() { update_scroll(); - _need_update = true; - _viewport->update(); + set_update(_time_viewport, true); + viewport_update(); //traces_moved(); } @@ -740,9 +863,18 @@ void View::set_cursor_middle(int index) set_scale_offset(_scale, (*i)->index() * 1.0 / _session.get_device()->get_sample_rate() - _scale * get_view_width() / 2); } -Viewport * View::get_viewport() +void View::on_measure_updated() { - return _viewport; + _active_viewport = dynamic_cast(sender()); + measure_updated(); +} + +QString View::get_measure(QString option) +{ + if (_active_viewport) { + return _active_viewport->get_measure(option); + } + return "#####"; } QString View::get_cm_time(int index) @@ -782,13 +914,16 @@ void View::on_cursor_moved() void View::set_measure_en(int enable) { - _viewport->set_measure_en(enable); + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->set_measure_en(enable); } void View::on_state_changed(bool stop) { - if (stop) - _viewport->stop_trigger_timer(); + if (stop) { + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->stop_trigger_timer(); + } } int View::get_view_width() @@ -800,7 +935,7 @@ int View::get_view_width() view_width = max((double)view_width, s->get_view_rect().width()); } } else { - view_width = _viewport->width(); + view_width = _viewcenter->width(); } return view_width; @@ -815,7 +950,7 @@ int View::get_view_height() view_height = max((double)view_height, s->get_view_rect().height()); } } else { - view_height = _viewport->width(); + view_height = _viewcenter->height(); } return view_height; @@ -846,5 +981,19 @@ void View::show_region(uint64_t start, uint64_t end) set_scale_offset(new_scale, new_off); } +void View::viewport_update() +{ + _viewcenter->update(); + BOOST_FOREACH(Viewport *viewport, _viewport_list) + viewport->update(); +} + +void View::splitterMoved(int pos, int index) +{ + (void)pos; + (void)index; + signals_changed(); +} + } // namespace view } // namespace pv diff --git a/DSView/pv/view/view.h b/DSView/pv/view/view.h index 1f903737..a90f8fb4 100644 --- a/DSView/pv/view/view.h +++ b/DSView/pv/view/view.h @@ -32,12 +32,15 @@ #include #include -#include +#include #include #include +#include +#include "../../extdef.h" #include "../toolbars/samplingbar.h" #include "../data/signaldata.h" +#include "../view/viewport.h" #include "cursor.h" #include "signal.h" @@ -57,7 +60,7 @@ class Ruler; class Trace; class Viewport; -class View : public QAbstractScrollArea { +class View : public QScrollArea { Q_OBJECT private: @@ -111,7 +114,7 @@ public: void set_scale_offset(double scale, double offset); void set_preScale_preOffset(); - std::vector< boost::shared_ptr > get_traces() const; + std::vector< boost::shared_ptr > get_traces(int type); /** * Returns true if cursors are displayed. false otherwise. @@ -164,11 +167,10 @@ public: double get_minscale() const; double get_maxscale() const; - void set_need_update(bool need_update); - bool need_update() const; + void set_update(Viewport *viewport, bool need_update); + void set_all_update(bool need_update); uint64_t get_cursor_samples(int index); - Viewport * get_viewport(); QString get_cm_time(int index); QString get_cm_delta(int index1, int index2); @@ -187,6 +189,11 @@ public: QString trigger_time(); + QString get_measure(QString option); + + void viewport_update(); + + signals: void hover_point_changed(); @@ -198,6 +205,8 @@ signals: void mode_changed(); + void measure_updated(); + private: void get_scroll_layout(double &length, double &offset) const; @@ -236,12 +245,22 @@ private slots: void set_trig_pos(quint64 trig_pos); + void on_measure_updated(); + + void splitterMoved(int pos, int index); + private: SigSession &_session; pv::toolbars::SamplingBar *_sampling_bar; - Viewport *_viewport; + QWidget *_viewcenter; + QSplitter *_vsplitter; + Viewport * _time_viewport; + Viewport * _fft_viewport; + Viewport *_active_viewport; + std::list _viewport_list; + std::map _trace_view_map; Ruler *_ruler; Header *_header; DevMode *_devmode; @@ -259,10 +278,7 @@ private: int _spanY; int _signalHeight; - int _v_offset; - bool _updating_scroll; - - bool _need_update; + bool _updating_scroll; bool _show_cursors; diff --git a/DSView/pv/view/viewport.cpp b/DSView/pv/view/viewport.cpp index 4f5b6f67..4ecbc294 100644 --- a/DSView/pv/view/viewport.cpp +++ b/DSView/pv/view/viewport.cpp @@ -21,13 +21,13 @@ */ -#include "view.h" #include "viewport.h" #include "ruler.h" #include "signal.h" #include "dsosignal.h" #include "logicsignal.h" +#include "mathtrace.h" #include "../device/devinst.h" #include "../data/logic.h" #include "../data/logicsnapshot.h" @@ -52,9 +52,11 @@ namespace view { const double Viewport::DragDamping = 1.05; const double Viewport::MinorDragRateUp = 10; -Viewport::Viewport(View &parent) : - QWidget(&parent), - _view(parent), +Viewport::Viewport(View &parent, View_type type) : + QWidget(&parent), + _view(parent), + _type(type), + _need_update(false), _total_receive_len(0), _action_type(NO_ACTION), _measure_type(NO_MEASURE), @@ -100,7 +102,7 @@ int Viewport::get_total_height() const { int h = 0; - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); h += (int)(t->get_totalHeight()); @@ -126,11 +128,13 @@ void Viewport::paintEvent(QPaintEvent *event) QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this); - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); BOOST_FOREACH(const boost::shared_ptr t, traces) { assert(t); t->paint_back(p, 0, _view.get_view_width()); + if (t->enabled() && _view.session().get_device()->dev_inst()->mode == DSO) + break; } p.setRenderHint(QPainter::Antialiasing, false); @@ -145,9 +149,11 @@ void Viewport::paintEvent(QPaintEvent *event) break; case SigSession::Running: - p.setRenderHint(QPainter::Antialiasing); - paintProgress(p); - p.setRenderHint(QPainter::Antialiasing, false); + if (_type == TIME_VIEW) { + p.setRenderHint(QPainter::Antialiasing); + paintProgress(p); + p.setRenderHint(QPainter::Antialiasing, false); + } break; } } else { @@ -172,11 +178,11 @@ void Viewport::paintEvent(QPaintEvent *event) void Viewport::paintSignals(QPainter &p) { - const vector< boost::shared_ptr > traces(_view.get_traces()); + const vector< boost::shared_ptr > traces(_view.get_traces(_type)); if (_view.scale() != _curScale || _view.offset() != _curOffset || _view.get_signalHeight() != _curSignalHeight || - _view.need_update()) { + _need_update) { _curScale = _view.scale(); _curOffset = _view.offset(); _curSignalHeight = _view.get_signalHeight(); @@ -190,15 +196,14 @@ void Viewport::paintSignals(QPainter &p) { assert(t); if (t->enabled()) - t->paint_mid(dbp, 0, _view.get_view_width()); + t->paint_mid(dbp, 0, t->get_view_rect().width()); } - - _view.set_need_update(false); + _need_update = false; } p.drawPixmap(0, 0, pixmap); // plot cursors - if (_view.cursors_shown()) { + if (_view.cursors_shown() && _type == TIME_VIEW) { list::iterator i = _view.get_cursorList().begin(); double cursorX; const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); @@ -212,22 +217,25 @@ void Viewport::paintSignals(QPainter &p) i++; } } - if (_view.trig_cursor_shown()) { - _view.get_trig_cursor()->paint(p, rect(), 0); - } - if (_view.search_cursor_shown()) { - _view.get_search_cursor()->paint(p, rect(), 0); - } - // plot zoom rect - if (_action_type == LOGIC_ZOOM) { - p.setPen(Qt::NoPen); - p.setBrush(Trace::dsLightBlue); - p.drawRect(QRectF(_mouse_down_point, _mouse_point)); - } + if (_type == TIME_VIEW) { + if (_view.trig_cursor_shown()) { + _view.get_trig_cursor()->paint(p, rect(), 0); + } + if (_view.search_cursor_shown()) { + _view.get_search_cursor()->paint(p, rect(), 0); + } - //plot measure arrow - paintMeasure(p); + // plot zoom rect + if (_action_type == LOGIC_ZOOM) { + p.setPen(Qt::NoPen); + p.setBrush(Trace::dsLightBlue); + p.drawRect(QRectF(_mouse_down_point, _mouse_point)); + } + + //plot measure arrow + paintMeasure(p); + } } void Viewport::paintProgress(QPainter &p) @@ -413,38 +421,51 @@ void Viewport::mouseMoveEvent(QMouseEvent *event) _hover_hit = false; if (event->buttons() & Qt::LeftButton) { - _view.set_scale_offset(_view.scale(), - _mouse_down_offset + - (_mouse_down_point - event->pos()).x() * - _view.scale()); - _drag_strength = (_mouse_down_point - event->pos()).x(); + if (_type == TIME_VIEW) { + _view.set_scale_offset(_view.scale(), + _mouse_down_offset + + (_mouse_down_point - event->pos()).x() * + _view.scale()); + _drag_strength = (_mouse_down_point - event->pos()).x(); + } else if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + double delta = (_mouse_point - event->pos()).x(); + t->set_offset(delta); + break; + } + } + } } - if (!(event->buttons() || Qt::NoButton)) { - if (_action_type == DSO_TRIG_MOVE) { - if (_drag_sig) { - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(_drag_sig)) - dsoSig->set_trig_vpos(event->pos().y()); + if (_type == TIME_VIEW) { + if (!(event->buttons() || Qt::NoButton)) { + if (_action_type == DSO_TRIG_MOVE) { + if (_drag_sig) { + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(_drag_sig)) + dsoSig->set_trig_vpos(event->pos().y()); + } } - } - if (_action_type == CURS_MOVE) { - uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); - if (_view.cursors_shown() && grabbed_marker) { - const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale(); - const double pos = cur_time * sample_rate; - const double pos_delta = pos - (uint64_t)pos; - if ( pos_delta < 0.5) - grabbed_marker->set_index((uint64_t)floor(pos)); - else - grabbed_marker->set_index((uint64_t)ceil(pos)); + if (_action_type == CURS_MOVE) { + uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + TimeMarker* grabbed_marker = _view.get_ruler()->get_grabbed_cursor(); + if (_view.cursors_shown() && grabbed_marker) { + const double cur_time = _view.offset() + _view.hover_point().x() * _view.scale(); + const double pos = cur_time * sample_rate; + const double pos_delta = pos - (uint64_t)pos; + if ( pos_delta < 0.5) + grabbed_marker->set_index((uint64_t)floor(pos)); + else + grabbed_marker->set_index((uint64_t)ceil(pos)); + } } - } - if (_action_type == DSO_YM) - _dso_ym_end = event->pos().y(); + if (_action_type == DSO_YM) + _dso_ym_end = event->pos().y(); + } } _mouse_point = event->pos(); @@ -457,177 +478,178 @@ void Viewport::mouseReleaseEvent(QMouseEvent *event) { assert(event); - if ((_action_type == NO_ACTION) && - (event->button() == Qt::LeftButton)) { - // priority 0 - if (_action_type == NO_ACTION && _view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); - double cursorX; - const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); - while (i != _view.get_cursorList().end()) { - cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); - if ((*i)->grabbed()) { - _view.get_ruler()->rel_grabbed_cursor(); - } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { - _view.get_ruler()->set_grabbed_cursor(*i); - _action_type = CURS_MOVE; - break; - } - i++; - } - } - - if (_view.session().get_device()->dev_inst()->mode == LOGIC && - _view.session().get_capture_state() == SigSession::Stopped) { - // priority 1 - if (_action_type == NO_ACTION) { - const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); - if (_time.elapsed() < 200 && - abs(_drag_strength) < MinorDragOffsetUp && - abs(strength) > MinorDragRateUp) { - _drag_strength = _drag_strength; - _drag_timer.start(DragTimerInterval); - _action_type = LOGIC_MOVE; - } else if (_time.elapsed() < 200 && - abs(strength) > DragTimerInterval) { - _drag_strength = strength * 5; - _drag_timer.start(DragTimerInterval); - _action_type = LOGIC_MOVE; + if (_type == TIME_VIEW) { + if ((_action_type == NO_ACTION) && + (event->button() == Qt::LeftButton)) { + // priority 0 + if (_action_type == NO_ACTION && _view.cursors_shown()) { + list::iterator i = _view.get_cursorList().begin(); + double cursorX; + const double samples_per_pixel = _view.session().get_device()->get_sample_rate() * _view.scale(); + while (i != _view.get_cursorList().end()) { + cursorX = (*i)->index()/samples_per_pixel - (_view.offset() / _view.scale()); + if ((*i)->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); + } else if (qAbs(cursorX - event->pos().x()) <= HitCursorMargin) { + _view.get_ruler()->set_grabbed_cursor(*i); + _action_type = CURS_MOVE; + break; + } + i++; } } - // priority 2 - if (_action_type == NO_ACTION) { - if (_mouse_down_point.x() == event->pos().x()) { + if (_view.session().get_device()->dev_inst()->mode == LOGIC && + _view.session().get_capture_state() == SigSession::Stopped) { + // priority 1 + if (_action_type == NO_ACTION) { + const double strength = _drag_strength*DragTimerInterval*1.0/_time.elapsed(); + if (_time.elapsed() < 200 && + abs(_drag_strength) < MinorDragOffsetUp && + abs(strength) > MinorDragRateUp) { + _drag_strength = _drag_strength; + _drag_timer.start(DragTimerInterval); + _action_type = LOGIC_MOVE; + } else if (_time.elapsed() < 200 && + abs(strength) > DragTimerInterval) { + _drag_strength = strength * 5; + _drag_timer.start(DragTimerInterval); + _action_type = LOGIC_MOVE; + } + } + + // priority 2 + if (_action_type == NO_ACTION) { + if (_mouse_down_point.x() == event->pos().x()) { + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { + _action_type = LOGIC_EDGE; + _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); + break; + } + } + } + } + } else if (_view.session().get_device()->dev_inst()->mode == DSO) { + // priority 0 + if (_action_type == NO_ACTION && _hover_hit) { + _action_type = DSO_YM; + _dso_ym_valid = true; + _dso_ym_sig_index = _hover_sig_index; + _dso_ym_sig_value = _hover_sig_value; + _dso_ym_index = _hover_index; + _dso_ym_start = event->pos().y(); + } + + // priority 1 + if (_action_type == NO_ACTION) { const vector< boost::shared_ptr > sigs(_view.session().get_signals()); BOOST_FOREACH(const boost::shared_ptr s, sigs) { assert(s); - if (abs(event->pos().y() - s->get_y()) < _view.get_signalHeight()) { - _action_type = LOGIC_EDGE; - _edge_start = (_view.offset() + (event->pos().x() + 0.5) * _view.scale()) * _view.session().get_device()->get_sample_rate(); - break; + if (!s->enabled()) + continue; + boost::shared_ptr dsoSig; + if (dsoSig = dynamic_pointer_cast(s)) { + if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { + _drag_sig = s; + _action_type = DSO_TRIG_MOVE; + break; + } } } } } - } else if (_view.session().get_device()->dev_inst()->mode == DSO) { - // priority 0 - if (_action_type == NO_ACTION && _hover_hit) { - _action_type = DSO_YM; - _dso_ym_valid = true; - _dso_ym_sig_index = _hover_sig_index; - _dso_ym_sig_value = _hover_sig_value; - _dso_ym_index = _hover_index; - _dso_ym_start = event->pos().y(); + } else if (_action_type == DSO_YM) { + if (event->button() == Qt::LeftButton) { + _dso_ym_end = event->pos().y(); + _action_type = NO_ACTION; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_ym_valid = false; } + } else if (_action_type == DSO_TRIG_MOVE) { + if (event->button() == Qt::LeftButton) { + _drag_sig.reset(); + _action_type = NO_ACTION; + } + } else if (_action_type == DSO_XM_STEP0) { + if (event->button() == Qt::LeftButton) { + _action_type = DSO_XM_STEP1; + _dso_xm_valid = true; + } + } else if (_action_type == DSO_XM_STEP1) { + if (event->button() == Qt::LeftButton) { + const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; - // priority 1 - if (_action_type == NO_ACTION) { - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - if (!s->enabled()) - continue; - boost::shared_ptr dsoSig; - if (dsoSig = dynamic_pointer_cast(s)) { - if (dsoSig->get_trig_rect(0, _view.get_view_width()).contains(_mouse_point)) { - _drag_sig = s; - _action_type = DSO_TRIG_MOVE; - break; - } + _dso_xm_index[1] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + const uint64_t max_index = max(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); + _dso_xm_index[1] = max_index; + + _action_type = DSO_XM_STEP2; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + measure_updated(); + } + } else if (_action_type == DSO_XM_STEP2) { + if (event->button() == Qt::LeftButton) { + const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const double scale = _view.scale(); + const double samples_per_pixel = sample_rate * scale; + _dso_xm_index[2] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; + const uint64_t max_index = max(_dso_xm_index[1], _dso_xm_index[2]); + _dso_xm_index[1] = min(_dso_xm_index[1], _dso_xm_index[2]); + _dso_xm_index[2] = max_index; + + _action_type = NO_ACTION; + } else if (event->button() == Qt::RightButton) { + _action_type = NO_ACTION; + _dso_xm_valid = false; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + measure_updated(); + } + } else if (_action_type == CURS_MOVE) { + _action_type = NO_ACTION; + if (_view.cursors_shown()) { + list::iterator i = _view.get_cursorList().begin(); + while (i != _view.get_cursorList().end()) { + if ((*i)->grabbed()) { + _view.get_ruler()->rel_grabbed_cursor(); } + i++; } } - } - } else if (_action_type == DSO_YM) { - if (event->button() == Qt::LeftButton) { - _dso_ym_end = event->pos().y(); + } else if (_action_type == LOGIC_EDGE) { _action_type = NO_ACTION; - } else if (event->button() == Qt::RightButton) { + _edge_rising = 0; + _edge_falling = 0; + } else if (_action_type == LOGIC_MOVE) { + _drag_strength = 0; + _drag_timer.stop(); _action_type = NO_ACTION; - _dso_ym_valid = false; - } - } else if (_action_type == DSO_TRIG_MOVE) { - if (event->button() == Qt::LeftButton) { - _drag_sig.reset(); - _action_type = NO_ACTION; - } - } else if (_action_type == DSO_XM_STEP0) { - if (event->button() == Qt::LeftButton) { - _action_type = DSO_XM_STEP1; - _dso_xm_valid = true; - } - } else if (_action_type == DSO_XM_STEP1) { - if (event->button() == Qt::LeftButton) { - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - - _dso_xm_index[1] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; - const uint64_t max_index = max(_dso_xm_index[0], _dso_xm_index[1]); - _dso_xm_index[0] = min(_dso_xm_index[0], _dso_xm_index[1]); - _dso_xm_index[1] = max_index; - - _action_type = DSO_XM_STEP2; - } else if (event->button() == Qt::RightButton) { - _action_type = NO_ACTION; - _dso_xm_valid = false; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - measure_updated(); - } - } else if (_action_type == DSO_XM_STEP2) { - if (event->button() == Qt::LeftButton) { - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const double scale = _view.scale(); - const double samples_per_pixel = sample_rate * scale; - _dso_xm_index[2] = event->pos().x() * samples_per_pixel + _view.offset() * sample_rate; - const uint64_t max_index = max(_dso_xm_index[1], _dso_xm_index[2]); - _dso_xm_index[1] = min(_dso_xm_index[1], _dso_xm_index[2]); - _dso_xm_index[2] = max_index; - - _action_type = NO_ACTION; - } else if (event->button() == Qt::RightButton) { - _action_type = NO_ACTION; - _dso_xm_valid = false; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - measure_updated(); - } - } else if (_action_type == CURS_MOVE) { - _action_type = NO_ACTION; - if (_view.cursors_shown()) { - list::iterator i = _view.get_cursorList().begin(); - while (i != _view.get_cursorList().end()) { - if ((*i)->grabbed()) { - _view.get_ruler()->rel_grabbed_cursor(); - } - i++; + } else if (_action_type == LOGIC_ZOOM) { + if (event->pos().x() != _mouse_down_point.x()) { + const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); + const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), + _view.get_maxscale()), _view.get_minscale()); + if (newScale != _view.scale()) + _view.set_scale_offset(newScale, newOffset); } + _action_type = NO_ACTION; } - } else if (_action_type == LOGIC_EDGE) { - _action_type = NO_ACTION; - _edge_rising = 0; - _edge_falling = 0; - } else if (_action_type == LOGIC_MOVE) { - _drag_strength = 0; - _drag_timer.stop(); - _action_type = NO_ACTION; - } else if (_action_type == LOGIC_ZOOM) { - if (event->pos().x() != _mouse_down_point.x()) { - const double newOffset = _view.offset() + (min(event->pos().x(), _mouse_down_point.x()) + 0.5) * _view.scale(); - const double newScale = max(min(_view.scale() * abs(event->pos().x() - _mouse_down_point.x()) / _view.get_view_width(), - _view.get_maxscale()), _view.get_minscale()); - if (newScale != _view.scale()) - _view.set_scale_offset(newScale, newOffset); - } - _action_type = NO_ACTION; } - update(); } @@ -676,16 +698,26 @@ void Viewport::wheelEvent(QWheelEvent *event) { assert(event); - if (event->orientation() == Qt::Vertical) { - // Vertical scrolling is interpreted as zooming in/out - const double offset = event->x(); - _view.zoom(event->delta() / 80, offset); - } else if (event->orientation() == Qt::Horizontal) { - // Horizontal scrolling is interpreted as moving left/right - _view.set_scale_offset(_view.scale(), - event->delta() * _view.scale() - + _view.offset()); - } + if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + t->zoom(event->delta() / 80, event->x()); + break; + } + } + } else if (_type == TIME_VIEW){ + if (event->orientation() == Qt::Vertical) { + // Vertical scrolling is interpreted as zooming in/out + const double offset = event->x(); + _view.zoom(event->delta() / 80, offset); + } else if (event->orientation() == Qt::Horizontal) { + // Horizontal scrolling is interpreted as moving left/right + _view.set_scale_offset(_view.scale(), + event->delta() * _view.scale() + + _view.offset()); + } + } measure(); } @@ -759,62 +791,72 @@ void Viewport::clear_measure() void Viewport::measure() { _measure_type = NO_MEASURE; - const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); - const vector< boost::shared_ptr > sigs(_view.session().get_signals()); - BOOST_FOREACH(const boost::shared_ptr s, sigs) { - assert(s); - boost::shared_ptr logicSig; - boost::shared_ptr dsoSig; - if (logicSig = dynamic_pointer_cast(s)) { - if (_action_type == NO_ACTION) { - if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { - _measure_type = LOGIC_FREQ; + if (_type == TIME_VIEW) { + const uint64_t sample_rate = _view.session().get_device()->get_sample_rate(); + const vector< boost::shared_ptr > sigs(_view.session().get_signals()); + BOOST_FOREACH(const boost::shared_ptr s, sigs) { + assert(s); + boost::shared_ptr logicSig; + boost::shared_ptr dsoSig; + if (logicSig = dynamic_pointer_cast(s)) { + if (_action_type == NO_ACTION) { + if (logicSig->measure(_mouse_point, _cur_sample, _nxt_sample, _thd_sample)) { + _measure_type = LOGIC_FREQ; - _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); - _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; - _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; + _mm_width = _view.get_ruler()->format_real_time(_nxt_sample - _cur_sample, sample_rate); + _mm_period = _thd_sample != 0 ? _view.get_ruler()->format_real_time(_thd_sample - _cur_sample, sample_rate) : "#####"; + _mm_freq = _thd_sample != 0 ? _view.get_ruler()->format_real_freq(_thd_sample - _cur_sample, sample_rate) : "#####"; - const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; - _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; - _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; - _cur_midY = logicSig->get_y(); + const double pixels_offset = _view.offset() / _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); + _cur_preX = _cur_sample / samples_per_pixel - pixels_offset; + _cur_aftX = _nxt_sample / samples_per_pixel - pixels_offset; + _cur_thdX = _thd_sample / samples_per_pixel - pixels_offset; + _cur_midY = logicSig->get_y(); - _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : - "#####"; + _mm_duty = _thd_sample != 0 ? QString::number((_nxt_sample - _cur_sample) * 100.0 / (_thd_sample - _cur_sample), 'f', 2)+"%" : + "#####"; + break; + } else { + _measure_type = NO_MEASURE; + _mm_width = "#####"; + _mm_period = "#####"; + _mm_freq = "#####"; + _mm_duty = "#####"; + } + } else if (_action_type == LOGIC_EDGE) { + if (logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { + const double pixels_offset = _view.offset() / _view.scale(); + const double samples_per_pixel = sample_rate * _view.scale(); + _cur_preX = _edge_start / samples_per_pixel - pixels_offset; + _cur_aftX = _view.hover_point().x(); + _cur_midY = logicSig->get_y() - logicSig->get_totalHeight()/2 - 5; + + _em_rising = "Rising: " + QString::number(_edge_rising); + _em_falling = "Falling: " + QString::number(_edge_falling); + _em_edges = "Edges: " + QString::number(_edge_rising + _edge_falling); + + break; + } + } + } else if (dsoSig = dynamic_pointer_cast(s)) { + if (_measure_en && dsoSig->measure(_view.hover_point())) { + _measure_type = DSO_VALUE; break; } else { _measure_type = NO_MEASURE; - _mm_width = "#####"; - _mm_period = "#####"; - _mm_freq = "#####"; - _mm_duty = "#####"; - } - } else if (_action_type == LOGIC_EDGE) { - if (logicSig->edges(_view.hover_point(), _edge_start, _edge_rising, _edge_falling)) { - const double pixels_offset = _view.offset() / _view.scale(); - const double samples_per_pixel = sample_rate * _view.scale(); - _cur_preX = _edge_start / samples_per_pixel - pixels_offset; - _cur_aftX = _view.hover_point().x(); - _cur_midY = logicSig->get_y() - logicSig->get_totalHeight()/2 - 5; - - _em_rising = "Rising: " + QString::number(_edge_rising); - _em_falling = "Falling: " + QString::number(_edge_falling); - _em_edges = "Edges: " + QString::number(_edge_rising + _edge_falling); - - break; } } - } else if (dsoSig = dynamic_pointer_cast(s)) { - if (_measure_en && dsoSig->measure(_view.hover_point())) { - _measure_type = DSO_VALUE; - break; - } else { - _measure_type = NO_MEASURE; + } + } else if (_type == FFT_VIEW) { + BOOST_FOREACH(const boost::shared_ptr t, _view.session().get_math_signals()) { + assert(t); + if(t->enabled()) { + t->measure(_view.hover_point()); } } } + measure_updated(); } @@ -1065,7 +1107,7 @@ void Viewport::paintMeasure(QPainter &p) p.drawLine(x[dso_xm_stage-1], _dso_xm_y, _mouse_point.x(), _dso_xm_y); p.drawLine(_mouse_point.x(), 0, - _mouse_point.x(), _view.get_viewport()->height()); + _mouse_point.x(), height()); } measure_updated(); } @@ -1179,5 +1221,11 @@ void Viewport::paintTrigTime(QPainter &p) } } +void Viewport::set_need_update(bool update) +{ + _need_update = update; +} + + } // namespace view } // namespace pv diff --git a/DSView/pv/view/viewport.h b/DSView/pv/view/viewport.h index 999c72a9..33ed45b2 100644 --- a/DSView/pv/view/viewport.h +++ b/DSView/pv/view/viewport.h @@ -30,8 +30,12 @@ #include #include #include + #include +#include "../../extdef.h" +#include "../view/view.h" + class QPainter; class QPaintEvent; class SigSession; @@ -81,7 +85,7 @@ public: }; public: - explicit Viewport(View &parent); + explicit Viewport(View &parent, View_type type); int get_total_height() const; @@ -96,6 +100,8 @@ public: void clear_measure(); + void set_need_update(bool update); + protected: void paintEvent(QPaintEvent *event); @@ -125,6 +131,8 @@ signals: private: View &_view; + View_type _type; + bool _need_update; uint64_t _total_receive_len; QPoint _mouse_point; diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index a31467a5..d39aebf0 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -247,6 +247,9 @@ static const uint64_t samplerates[] = { // SR_MB(4), // SR_MB(8), // SR_MB(16), +// SR_MB(32), +// SR_MB(64), +// SR_MB(128), //}; static const uint64_t samplecounts[] = { @@ -270,10 +273,10 @@ static const uint64_t samplecounts[] = { /* We name the probes 0-7 on our demo driver. */ static const char *probe_names[NUM_PROBES + 1] = { - "Channel 0", "Channel 1", "Channel 2", "Channel 3", - "Channel 4", "Channel 5", "Channel 6", "Channel 7", - "Channel 8", "Channel 9", "Channel 10", "Channel 11", - "Channel 12", "Channel 13", "Channel 14", "Channel 15", + "CH0", "CH1", "CH2", "CH3", + "CH4", "CH5", "CH6", "CH7", + "CH8", "CH9", "CH10", "CH11", + "CH12", "CH13", "CH14", "CH15", NULL, }; diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index e55adbb0..c6c9e01e 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -549,6 +549,7 @@ enum { SR_CHANNEL_ANALOG, SR_CHANNEL_GROUP, SR_CHANNEL_DECODER, + SR_CHANNEL_FFT, }; enum { @@ -560,7 +561,7 @@ enum { struct sr_channel { /* The index field will go: use g_slist_length(sdi->channels) instead. */ uint16_t index; - int type; + int type; gboolean enabled; char *name; char *trigger;