From 96b511fb4c0a7dcda2f264dc75f0da26eac5c2e4 Mon Sep 17 00:00:00 2001 From: yunyaobaihong <896458252@qq.com> Date: Thu, 4 May 2023 10:46:56 +0800 Subject: [PATCH 1/4] demo --- DSView/pv/mainwindow.cpp | 106 +- DSView/pv/mainwindow.h | 5 + DSView/pv/sigsession.cpp | 29 + DSView/res/demo/demo_eeprom.dsl | Bin 0 -> 76550 bytes DSView/res/demo/demo_sawtooth_analog.dsl | Bin 0 -> 1205 bytes DSView/res/demo/demo_sawtooth_dso.dsl | Bin 0 -> 1725 bytes DSView/res/demo/demo_sine_analog.dsl | Bin 0 -> 1195 bytes DSView/res/demo/demo_sine_dso.dsl | Bin 0 -> 1849 bytes DSView/res/demo/demo_spi.dsl | Bin 0 -> 147779 bytes DSView/res/demo/demo_square_analog.dsl | Bin 0 -> 1003 bytes DSView/res/demo/demo_square_dso.dsl | Bin 0 -> 2279 bytes DSView/res/demo/demo_triangle_analog.dsl | Bin 0 -> 1219 bytes DSView/res/demo/demo_triangle_dso.dsl | Bin 0 -> 1829 bytes DSView/res/demo/demo_uart.dsl | Bin 0 -> 155058 bytes libsigrok4DSL/hardware/demo/demo.c | 2953 ++++++++++++++++------ libsigrok4DSL/hardware/demo/demo.h | 199 +- libsigrok4DSL/lib_main.c | 3 +- libsigrok4DSL/libsigrok.h | 7 + 18 files changed, 2485 insertions(+), 817 deletions(-) create mode 100644 DSView/res/demo/demo_eeprom.dsl create mode 100644 DSView/res/demo/demo_sawtooth_analog.dsl create mode 100644 DSView/res/demo/demo_sawtooth_dso.dsl create mode 100644 DSView/res/demo/demo_sine_analog.dsl create mode 100644 DSView/res/demo/demo_sine_dso.dsl create mode 100644 DSView/res/demo/demo_spi.dsl create mode 100644 DSView/res/demo/demo_square_analog.dsl create mode 100644 DSView/res/demo/demo_square_dso.dsl create mode 100644 DSView/res/demo/demo_triangle_analog.dsl create mode 100644 DSView/res/demo/demo_triangle_dso.dsl create mode 100644 DSView/res/demo/demo_uart.dsl diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index d72faed7..b155c593 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -116,6 +116,9 @@ namespace pv _is_auto_switch_device = false; _is_save_confirm_msg = false; + _demo_load_decoder = TRUE; + _demo_auto_start = FALSE; + setup_ui(); setContextMenuPolicy(Qt::NoContextMenu); @@ -1674,6 +1677,11 @@ namespace pv break; case DSV_MSG_START_COLLECT_WORK: + /*demo下逻辑分析仪采集一次后,设置自动采集*/ + if (_device_agent->is_demo() && _device_agent->get_work_mode() == LOGIC) + { + _demo_auto_start = TRUE; + } update_toolbar_view_status(); _view->on_state_changed(false); _protocol_widget->update_view_status(); @@ -1712,13 +1720,20 @@ namespace pv _session->device_event_object()->device_updated(); if (_device_agent->is_hardware()) + { + /*切换到硬件设备,取消demo的自动采集*/ + _demo_auto_start = FALSE; _session->on_load_config_end(); + } + if (_device_agent->get_work_mode() == LOGIC && _device_agent->is_file() == false) _view->auto_set_max_scale(); if (_device_agent->is_file()) { + /*切换到硬件设备,取消demo的自动采集(目前使用gboolean类型需要includeligsigork)*/ + _demo_auto_start = FALSE; check_session_file_version(); bool bDoneDecoder = false; @@ -1731,7 +1746,27 @@ namespace pv } _session->start_capture(true); - } + } + + if (_device_agent->is_demo()) + { + /*demo下逻辑分析仪如果信号模式不为RANDOM,导入解码器*/ + if(_device_agent->get_work_mode() == LOGIC) + { + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_LOAD_DECODER); + if(gvar != NULL) + { + gboolean load_decoder = g_variant_get_boolean(gvar); + if(load_decoder) + { + //加载解码器 + StoreSession ss(_session); + QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); + ss.load_decoders(_protocol_widget, deArray); + } + } + } + } } break; @@ -1746,10 +1781,11 @@ namespace pv _view->timebase_changed(); break; - case DSV_MSG_DEVICE_MODE_CHANGED: + case DSV_MSG_DEVICE_MODE_CHANGED: _view->mode_changed(); reset_all_view(); - load_device_config(); + load_device_config(); + update_toolbar_view_status(); _sampling_bar->update_sample_rate_list(); @@ -1758,6 +1794,26 @@ namespace pv if (_device_agent->get_work_mode() == LOGIC) _view->auto_set_max_scale(); + + if(_device_agent->is_demo()) + { + /*demo下逻辑分析仪如果信号模式不为RANDOM,导入解码器*/ + _protocol_widget->del_all_protocol(); + if(_device_agent->get_work_mode() == LOGIC) + { + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_LOAD_DECODER); + if(gvar != NULL) + { + gboolean load_decoder = g_variant_get_boolean(gvar); + if(load_decoder) + { + StoreSession ss(_session); + QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); + ss.load_decoders(_protocol_widget, deArray); + } + } + } + } break; case DSV_MSG_NEW_USB_DEVICE: @@ -1838,9 +1894,49 @@ namespace pv } break; - case DSV_MSG_END_DEVICE_OPTIONS: - break; + case DSV_MSG_END_DEVICE_OPTIONS: + if(_device_agent->is_demo()) + { + /*信号模式发生修改,更新界面*/ + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_DEMO_CHANGE); + if(gvar != NULL) + { + gboolean pattern_change = g_variant_get_boolean(gvar); + if(pattern_change) + { + reset_all_view(); + load_device_config(); + update_toolbar_view_status(); + _device_agent->set_config(NULL,NULL,SR_CONF_DEMO_CHANGE,g_variant_new_boolean(FALSE)); + } + } + /*demo下逻辑分析仪如果信号模式不为RANDOM,导入解码器*/ + _protocol_widget->del_all_protocol(); + if(_device_agent->get_work_mode() == LOGIC) + { + _view->auto_set_max_scale(); + + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_LOAD_DECODER); + if(gvar != NULL) + { + gboolean load_decoder = g_variant_get_boolean(gvar); + if(load_decoder) + { + StoreSession ss(_session); + QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); + ss.load_decoders(_protocol_widget, deArray); + } + } + + /*demo下逻辑分析仪执行一次采集后,切换信号模式自动采集*/ + if(_demo_auto_start) + { + _session->start_capture(true); + } + } + } + break; } } diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index 7b7ea75c..eafdc6c3 100644 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -33,6 +33,9 @@ #include #include +//没有gboolean类型? +#include "libsigrok.h" + class QAction; class QMenuBar; class QMenu; @@ -214,6 +217,8 @@ private: bool _is_auto_switch_device; high_resolution_clock::time_point _last_key_press_time; bool _is_save_confirm_msg; + gboolean _demo_load_decoder; + gboolean _demo_auto_start; int _key_value; bool _key_vaild; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index aed5bbbf..157efa01 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -1950,6 +1950,31 @@ namespace pv switch (msg) { case DSV_MSG_DEVICE_OPTIONS_UPDATED: + if(_device_agent.is_demo()) + { + GVariant *gvar = _device_agent.get_config(NULL,NULL,SR_CONF_DEMO_CHANGE); + if(gvar != NULL) + { + gboolean pattern_change = g_variant_get_boolean(gvar); + if(pattern_change) + { + /*底层重置工作参数*/ + _device_agent.set_config(NULL,NULL,SR_CONF_DEMO_INIT,g_variant_new_boolean(TRUE)); + + _device_agent.update(); + + clear_all_decoder(); + + _capture_data->clear(); + _view_data->clear(); + _capture_data = _view_data; + + init_signals(); + set_cur_snap_samplerate(_device_agent.get_sample_rate()); + set_cur_samplelimits(_device_agent.get_sample_limit()); + } + } + } reload(); break; @@ -2069,6 +2094,7 @@ namespace pv // Nonthing. } + //** bool SigSession::switch_work_mode(int mode) { assert(!_is_working); @@ -2077,6 +2103,7 @@ namespace pv if (cur_mode != mode) { GVariant *val = g_variant_new_int16(mode); + /*底层重置工作参数*/ _device_agent.set_config(NULL, NULL, SR_CONF_DEVICE_MODE, val); if (cur_mode == LOGIC){ @@ -2104,7 +2131,9 @@ namespace pv set_cur_samplelimits(_device_agent.get_sample_limit()); dsv_info("Switch work mode to:%d", mode); + broadcast_msg(DSV_MSG_DEVICE_MODE_CHANGED); + return true; } return false; diff --git a/DSView/res/demo/demo_eeprom.dsl b/DSView/res/demo/demo_eeprom.dsl new file mode 100644 index 0000000000000000000000000000000000000000..5f6aab5223f5543325a9eae49cd1440754c3ded0 GIT binary patch literal 76550 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 Jx*gab>_4TdJ&ynY literal 0 HcmV?d00001 diff --git a/DSView/res/demo/demo_sawtooth_analog.dsl b/DSView/res/demo/demo_sawtooth_analog.dsl new file mode 100644 index 0000000000000000000000000000000000000000..64bbd87f5505fa9a1b689b53483c53de10182e79 GIT binary patch literal 1205 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 B%YXm? literal 0 HcmV?d00001 diff --git a/DSView/res/demo/demo_sine_dso.dsl b/DSView/res/demo/demo_sine_dso.dsl new file mode 100644 index 0000000000000000000000000000000000000000..12be47712f9fe7cba43a954a812035597313a224 GIT binary patch literal 1849 zcmWIWW@Zs#U}NB5*qGNB#_8mLrht)w!Je4`D8|5$k(!v2S`<6sU|zFl+Z z6%-qt^FyzCU-ixp*t}Sm8Qw#W05f{=k+43o)?*kFvMe(e+fd89L6XnDp2;rR+_kB(@T3aT4b`&IYP zsrb&nd;*J~eE>?F2d#ys4HsByC1MV_4St) zR@&LU_GNGp-;UCht`u9`j0+U3VqQ*lb&PcU|ieAzS%)#agC-pwy#@%`+c= z)Ls_Vy~Zq>t^Z`h^KQ#akJ=9{&vAS=^Fh>wLo3(FX*|F1>O}9`^A;bfc0}51UF?dR zrPjyrj^kM0*@kCJqTa1b-E&d%+yuc30tHpqoz@DfR!d~dIULKbxFo>!XinKS{`)r{ zHcnb|^U^kRjalg$=MC+SN=!UDN#IG({7v)A)h_-JIVF{4W}&gd_ReK5&da$!p0O_3 zAyOSZOC;5=%SL~0OLJnraO@q|mQ$0S)W1zyaeeoX)R_6PF;%}eHKjy)Ec$o;@FBjl zVXmpurcQ4ER%UHA^IE{m{v9f0Pk3RlKe2CT z#GiSyd}f_lv^?(1Oa2wkmFN0z{QqhD*+}V^dYy}lxZo@Px`@BqH*ddbjT)Z^=1A;U z0mi3*Is*eRN*Vlh4fGA(&g!*06d=+5{=%xY*V?^Kx~RCc2q<;AsAx{L3yU@le^I_@ z^@lmqKmKoYwy134 zX>qToUSIcqy!r0i*M*6G%cgzRon|_>$2ZyHMeWwv@>{c({s}noeADvd?Z0<-p8a~& z!{WvF%8=zsN@CX`wq@{mcNKqs;O;(Vg?5i^{{@2 z*f(ZE!Du)djKl>aBNGDy?)m|kBpHCo6AB=;MSwS|9`y1Hq!^-S3Xp=8X6U-mOEQG6 w13+ESat&P*dUio*ngFcOz?p}5E!TksuD>oYp#*rdg34cD1_VN&<#J#i0F~_#(EtDd literal 0 HcmV?d00001 diff --git a/DSView/res/demo/demo_spi.dsl b/DSView/res/demo/demo_spi.dsl new file mode 100644 index 0000000000000000000000000000000000000000..2d67addb93c277e17ed94f725a754962f4e65ea1 GIT binary patch literal 147779 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 EKg2d`CIA2c literal 0 HcmV?d00001 diff --git a/DSView/res/demo/demo_square_analog.dsl b/DSView/res/demo/demo_square_analog.dsl new file mode 100644 index 0000000000000000000000000000000000000000..552862a1fc9ce1762c6abe642f900751bebf2937 GIT binary patch literal 1003 zcmWIWW@Zs#U}NB5Xvv!q_I11V>lX|R44W7kfMN^`8L5dWsYSkhhIxk#cwEcpIf;8H z?lzdPG`d~Sad{c1(FL)$TvK%&r?o09U+=Lx&-~wUeY;rWqgQ`DWh)KPek+&vO_p_XjY`$~RNGobX`H_W;rayEocKet< z3!j~OC93(<`^P(igf7f;JS$-*ru{Sc66^atZ{~T$#!WePRPT%*yGZ%w*Jb6r``=03 z)Lk62Dv$C1ojLsG?aqhyYv-lazmpF@35z@l`TL+SU;$zdAWlh5&IblYard*Xr%Vi} zY9~qDFDwOynL1E0J5X(LYH@L9e%{f^*8YbLL|VW9>(W@WWz*-ZLtgA`TA?CZDpwBr z<^_BA$p)#5tom1;^E@!+RExm8HNS6~Kc6Qo@7@>njz?-%Q}yE=ylYc@Z&)-t?YJKQ zGA89$%XQKBoaeJA%?`S8_1TjLcNou>2W>xezP6clqL9`*kzDTbpHY*!s&=Wko;={` zdiJa>KkLS$T1vfEJyjn(RE?M3EOLE#HuJ-g`3pWCUVD9hgyYubP1>q;>iTyD&o!<* z)h+4MUnf&`tRuuAFg)t7=z(L0cf4Mi<59`R z-Z~*v-@~$5cjZjEzlUs(PF>wqD#ssxx#88zW8x=-mmfPdRd@d6Lp!ehw%9WH{Zcjw z#Ve{d3)B|-w(ER6J8el&#_k+_y9Gkr8^c+A|7124Snwu2d92VGU=mSh_5HUcd&{IF z+;1K0W;g5pm|yhcTm9cezKP;$g%4USIv)xAJZZ_cIeL5I4#_32X1)rz9ll9!uG@Un zn2B_An8XK+5i?-yumWjET?2iC+gm#A4)p6a*wx+K!U>E@MkWRZ+?fEVivg$`3Lsem zT@QL<0V#&);Q>;xq=T*tJ=q|1SpaoG6A`*5bRQu!T>^Ro?7skSR#3_XCS4YWOF){L H8N>qsZvJp= literal 0 HcmV?d00001 diff --git a/DSView/res/demo/demo_square_dso.dsl b/DSView/res/demo/demo_square_dso.dsl new file mode 100644 index 0000000000000000000000000000000000000000..32908e8f154c09afe9d3c687805ba097c9da52f7 GIT binary patch literal 2279 zcmWIWW@Zs#U}NB5n9@=g_9o(hbSfhQg9S4KP>g{gBQ-H4wJ3DLe!s&80`2AYt?>++ zhD)b3@+yiQITTh}Fv&aV;gM;N*^XQ;F5l*S>*c=te+z%j4d>`C{OtO~$?kM@p`2s6 zfZif*w&F8k!jD34@8(lew~FxPE-I2uSS_~p+efJd=F@gu4(xuhXj{?6$=f$v2x#3u z=hp)%zED1?*SGZN31uq3I5B;-*S`IKyFMOWbDOu#^Z%3vzQ->`X3tE%IK$(+pAwrf z&kz1R%IjG6#};ZPUh8FTiaK#EcCYE@357@1cP_bIRC_hIWZ@UPUv-TqmiXQHd&J%B zlR(dFj;oHc8Mn6^^9yr#&Of)ge~0DFnORyFg|Ba2C8~S#OvoXwY2_7fp26mv@;?&~e%>2Bg zll`*~D@YuB|5rqDcb@BHwal`2iS43nvZ)4D8&2-_@z}Ci?RW66yUX2XKjKKvG4TIn z_v^zI^S2)BkTx2@*TH(!#3A!uSdu3EqRIbyjTp6Aay+?ITmgiFMz@%*NPhxi% z*3MhH?GXRD2Ynu#O{~88g6ra! z=FhQ>ic_8ke!70+&jG&M(|`Xo&&izf)(4f^WV2j-@m=D&1cu+3z6sR6W$)* zY;$binfG%qPrP9N&``)qdZXRr#83HZ$4{!GM*{%tHw3=9J53=F`yWboHD&^LH{ z(=ZR1`CKka|Jq=e*mPi$$G@ll0+W|akPbH9?cX7y;CkUw^hwa=bLcH^_~%nRM>n{_zy7& zO`CDzp365A6~)BP2G?Ar-%Kx+g{FOpyE^N{zMxw@EvmZV)6_QU&(u>%^jv;*Zs(iq z<({4qml9?JZI#ZDpS&R@|E-kp&G$=k{SHmi-Ky)8vVUnAE2nqaB|GzpfA8HgQPH{S z;G3iLn{BnW(6lRl(}Ct*KGoNvs(QIiZBzcvRX}r>ewo?%rh0vbXGD;K(99EY4%bw4 z7AAIfzVUVOKO`g|HRD9w$m@RryXA0`NsK&lyc(9t+VI(q|86{T!z#8 z+|?fmO222=v3W)mj@};)a~ec&?_F0 zVu+qjAO)+2&~>3#K?q%2fx4g-61pbz;trvy4%qwv7kP@sZSPVtz9nefZoKk_cWNj%bK4eIskM)D3=~!7Usx&n{6U89hL^ieIepo? zU|Z9@pAVz0HhfoB+jlwR>$iq`YWLR)jQ+IE>gbvby+#@{&!M0 zbr;91%47V0XAZx4yYu1w+Iea9@8kne!Xi&X{yr!SSb&%Vh*MIN^MQd;-2JTUDH8*# z+L8ltjpe{F(*!DJ2dXVjEiTT?&pSHVI{%P?NNahW>y&k@H!CNW=sLG6Ep!T8+I3K6 zdcw(#%8!?9>G&UKt*4NYPkMEkr)r;y>&XM2 zu19B2mg7q5_FOdUpTVnxU0Q1wyq~FiUF6;zDgQs5QucSN|Mr=lU>1#e|8Y0lW!r}` zGuG`fTRiij|KU{|l|+3)F1@(NkYn3pZOVN1`71qdx5{a>s9jXmS5wf z8U&qUk1?+@jw(NqweQ}<5YFW3Z;!HjY!qPky>Mhc8%O(P1vfjsNgS@tPoH<+J8!8l zMI|nS|I=-mH*Nnl+w=clmwzTunJB~_*D+axZ{qxzq>QlHW<2K2A@(7{S--u^7Jq&r zj2bs{q`ojc0mcazFn(Bpw4<(pzCrBy*L+S13=9|C*Q_YHc-F`m2z;m4&YU?@Z&EF1 zr^}?s{D}J3dk!)t>3ho+hjA_ zbCL!Z)A?eV(?&eL!6KeQM^cQWc-j8eZSPK8E7oNuwRL@!tmCY+WxFrG{8~_BA=A&9 zWTooawJ5VKF|zM*rK5nW=cK1UYj(0c_@5NH?X88tu655@9VOf@zMZx#a@up(kJUec zNtBU^fdO~s28IO#FifBTlGV}mpl1S*Vu&6dAO*`3=(^Ce145StP!}|Fpld>pCxoUe aKyQF!Ex?-(l z0wx`}uy)n1kl0cs$>g#}oN`^AR$qJ}+xd>>`j+i+k~>!vnr#ROZi_#2 z?wr{iouoyE+x|Y&6I7e?X^-XUC&z!!-?8si>Ft9CtL{%(aCC>&lCMWHFJ}1v)_OQs zj_ptLO`-Ir{B#+w86n9H3gVl#Zol~=vt!32Prl6UG514Wul3$~eqa0nV^Ptt{U1)a z8C&F9A4`s%?ymT}?9sDV0bHH>&u?+EyW0l(C}us{q4oOm<_T&__sljlJrsPmt9he+ z=C4)lueV)2dUKP8_MUt8i=@Th>74o%A;Mn6qOos|xM+8ZbL9jf9#@YxrAdl>-`j$8 zC6aFOmIRm;;DYQj_z6@lo9Utm`Qg1FBlaFaf?Lz^FUU%D})5R9l={ zT%4JocQn{B`;dXizTetj<#$ywbF<68Z8*&0IPu_z30w0`FQ^G!KIi-Az4xsnUT%_) z5-eN4KdpUVeZShW&!+T`q=^ah|BIicwNiXfwaaL|yC1)(c;0LA8!YoVwX=d=1PIK$ zF-K;P`hufjSz3RRIK^DN1kS9s;;L6&aZ2ytBk!QMULTC&HtPwmeB97yA8_x>_ijDO@=#-@Phf|7 zX3wL|&dcZJ-!N;rWYY2PmRb0Qt#6Ol{5!kNqT|v_m5u@_e`S$nd$Zr>Uaoxpe8S5A z3(_yVUCU7k-nM(2 zZcR=9Bk{{cqjlPQb3)70T`DI{<;SG z25)DviXCzgaL(@#Z-1oAcU1G8-qF1QcOJILw8$jhe|JvBUhzrL#t1F-5UIJ1Ced%F zTz>nN-Fad}lkan`rCw_gCBoQwx!1N$7V z9lTcrc*HfNTx5T;B}pyuJ@HQwmq48UXw1(2E{z#CN$dVvK}4AIjMq+rDtx-Rsh3!!T_P#3fyL)U~J n#|TX=z{(4pX^7Wy99Y8o>jD!=fHy0szy)SJAOu>@1?B+&Iy>F; literal 0 HcmV?d00001 diff --git a/DSView/res/demo/demo_uart.dsl b/DSView/res/demo/demo_uart.dsl new file mode 100644 index 0000000000000000000000000000000000000000..2ec5557274cff527ac7b631026f33693501d98d9 GIT binary patch literal 155058 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 1) + { + cur_sample_generator = pre_sample_generator = PATTERN_DEFAULT; + strcat(dir_str,pattern_strings_logic[1]); + strcat(dir_str,".dsl"); + sdi->mode = LOGIC; + sdi->path = g_strdup(dir_str); + } + else + { + cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; + sdi->mode = LOGIC; + sdi->path = g_strdup(""); + } +} + +//通过信号模式索引获取文件名 +static char* get_dsl_path_by_pattern_mode(uint8_t device_mode , uint8_t pattern_mode) +{ + unzFile archive = NULL; + int index = -1; + char *str = g_try_malloc0(500); + strcpy(str,DS_RES_PATH); + strcat(str,"demo/"); + + if (pattern_mode != PATTERN_RANDOM) + { + switch (device_mode) + { + case LOGIC: + if(NULL != pattern_strings_logic[pattern_mode]) + { + strcat(str,pattern_strings_logic[pattern_mode]); + } + break; + case DSO: + if(NULL != pattern_strings_dso[pattern_mode]) + { + strcat(str,pattern_strings_dso[pattern_mode]); + } + break; + case ANALOG: + if(NULL != pattern_strings_analog[pattern_mode]) + { + strcat(str,pattern_strings_analog[pattern_mode]); + } + break; + default: + break; + } + strcat(str,".dsl"); + } + + if(pattern_mode != PATTERN_RANDOM) + { + //检查文件是否有效 + archive = unzOpen64(str); + if (NULL != archive) + { + return str; + } + else + { + return ""; + } + } + else + { + return NULL; + } +} + +static void adjust_samplerate(struct sr_dev_inst *sdi) +{ + if(sdi->mode == LOGIC && cur_sample_generator > PATTERN_RANDOM) + { + return; + } + + struct session_vdev *vdev = sdi->priv; + int cur_mode = -1; + if(sdi->mode == LOGIC) + cur_mode = 0; + else if(sdi->mode == DSO) + cur_mode = 2; + else if(sdi->mode == ANALOG) + cur_mode = 1; + + if(cur_mode == -1) + return; + + vdev->samplerates_max_index = ARRAY_SIZE(samplerates) - 1; + while (samplerates[vdev->samplerates_max_index] > + channel_modes_f[cur_mode].max_samplerate) + vdev->samplerates_max_index--; + + vdev->samplerates_min_index = 0; + while (samplerates[vdev->samplerates_min_index] < + channel_modes_f[cur_mode].min_samplerate) + vdev->samplerates_min_index++; + + assert(vdev->samplerates_max_index >= vdev->samplerates_min_index); + + if (vdev->samplerate > samplerates[vdev->samplerates_max_index]) + vdev->samplerate = samplerates[vdev->samplerates_max_index]; + + if (vdev->samplerate < samplerates[vdev->samplerates_min_index]) + vdev->samplerate = samplerates[vdev->samplerates_min_index]; + +} + +//初始化random数据 +static int init_random_data(struct session_vdev * vdev) +{ + uint8_t random_val; + if(vdev->logic_buf != NULL) + { + g_free(vdev->logic_buf); + } + if(!(vdev->logic_buf = g_try_malloc0(SR_MB(10)))) + { + return SR_ERR; + } + vdev->logic_buf_len = SR_MB(10); + for(int i = 0 ; i < vdev->logic_buf_len ;i++) + { + random_val = abs(rand())%256; + if(random_val >= 128) + { + *(uint8_t*)(vdev->logic_buf + i) = (uint8_t)255; + } + else + { + *(uint8_t*)(vdev->logic_buf + i) = (uint8_t)0; + } + } + return; +} + static int hw_init(struct sr_context *sr_ctx) { - return std_hw_init(sr_ctx, di, LOG_PREFIX); -} - -static void adjust_samplerate(struct demo_context *devc) -{ - devc->samplerates_max_index = ARRAY_SIZE(samplerates) - 1; - while (samplerates[devc->samplerates_max_index] > - channel_modes[devc->ch_mode].max_samplerate) - devc->samplerates_max_index--; - - devc->samplerates_min_index = 0; - while (samplerates[devc->samplerates_min_index] < - channel_modes[devc->ch_mode].min_samplerate) - devc->samplerates_min_index++; - - assert(devc->samplerates_max_index >= devc->samplerates_min_index); - - if (devc->cur_samplerate > samplerates[devc->samplerates_max_index]) - devc->cur_samplerate = samplerates[devc->samplerates_max_index]; - - if (devc->cur_samplerate < samplerates[devc->samplerates_min_index]) - devc->cur_samplerate = samplerates[devc->samplerates_min_index]; -} - -static void probe_init(struct sr_dev_inst *sdi) -{ - GSList *l; - struct demo_context *devc = sdi->priv; - - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - probe->bits = channel_modes[devc->ch_mode].unit_bits; - probe->vdiv = 1000; - probe->vfactor = 1; - probe->coupling = SR_AC_COUPLING; - probe->trig_value = (1 << (probe->bits - 1)); - probe->hw_offset = (1 << (probe->bits - 1)); - probe->offset = probe->hw_offset + - (probe->index - (channel_modes[devc->ch_mode].num - 1) /2.0) * (1 << (probe->bits - 2)); - - probe->map_default = TRUE; - probe->map_unit = probeMapUnits[0]; - probe->map_min = -(probe->vdiv * probe->vfactor * DS_CONF_DSO_VDIVS / 2000.0); - probe->map_max = probe->vdiv * probe->vfactor * DS_CONF_DSO_VDIVS / 2000.0; - } -} - -static int setup_probes(struct sr_dev_inst *sdi, int num_probes) -{ - uint16_t j; - struct sr_channel *probe; - struct demo_context *devc = sdi->priv; - - for (j = 0; j < num_probes; j++) { - if (!(probe = sr_channel_new(j, channel_modes[devc->ch_mode].type, - TRUE, probe_names[j]))) - return SR_ERR; - sdi->channels = g_slist_append(sdi->channels, probe); - } - probe_init(sdi); - return SR_OK; + return std_hw_init(sr_ctx, di, LOG_PREFIX); } static GSList *hw_scan(GSList *options) { struct sr_dev_inst *sdi; - struct drv_context *drvc; - struct demo_context *devc; + struct session_vdev *vdev; GSList *devices; + char str[500]; (void)options; - drvc = di->priv; devices = NULL; sr_info("%s", "Scan demo device."); - if (!(devc = g_try_malloc(sizeof(struct demo_context)))) { - sr_err("Device context malloc failed."); - return NULL; + vdev = g_try_malloc0(sizeof(struct session_vdev)); + if (vdev == NULL) + { + sr_err("%s: sdi->priv malloc failed", __func__); + return SR_ERR_MALLOC; } - devc->profile = &supported_Demo[0]; - devc->sample_generator = devc->profile->dev_caps.default_pattern; - devc->max_height = 0; - devc->limit_msec = 0; - - sdi = sr_dev_inst_new(LOGIC, - SR_ST_INITIALIZING, - devc->profile->vendor, - devc->profile->model, - devc->profile->model_version); + sdi = sr_dev_inst_new(LOGIC, SR_ST_INACTIVE, + supported_Demo[0].vendor, + supported_Demo[0].model, + supported_Demo[0].model_version); if (!sdi) { - g_free(devc); + g_free(vdev); sr_err("Device instance creation failed."); return NULL; } - - sdi->priv = devc; + sdi->priv = vdev; sdi->driver = di; sdi->dev_type = DEV_TYPE_DEMO; - init_demo_device(sdi); + devices = g_slist_append(devices, sdi); - devices = g_slist_append(devices, sdi); return devices; } -static void init_demo_device(struct sr_dev_inst *sdi) -{ - struct demo_context *devc; - int num_probes; - int i; - - assert(sdi); - assert(sdi->priv); - assert(sdi->dev_type == DEV_TYPE_DEMO); - - devc = sdi->priv; - - for (i = 0; i < ARRAY_SIZE(channel_modes); i++) { - if ((int)channel_modes[i].mode == sdi->mode && - devc->profile->dev_caps.channels & (1 << i)) { - devc->ch_mode = channel_modes[i].id; - break; - } - } - - num_probes = channel_modes[devc->ch_mode].num; - devc->cur_samplerate = channel_modes[devc->ch_mode].default_samplerate; - devc->limit_samples = channel_modes[devc->ch_mode].default_samplelimit; - devc->limit_samples_show = devc->limit_samples; - devc->timebase = devc->profile->dev_caps.default_timebase; - adjust_samplerate(devc); - - sr_dev_probes_free(sdi); - setup_probes(sdi, num_probes); -} - -static void reset_demo_device(struct sr_dev_inst *sdi) -{ - assert(sdi); - assert(sdi->priv); - assert(sdi->dev_type == DEV_TYPE_DEMO); - - sdi->mode = LOGIC; - - init_demo_device(sdi); -} - static const GSList *hw_dev_mode_list(const struct sr_dev_inst *sdi) { - struct demo_context *devc; + // struct demo_context *devc; GSList *l = NULL; unsigned int i; - devc = sdi->priv; for (i = 0; i < ARRAY_SIZE(sr_mode_list); i++) { - if (devc->profile->dev_caps.mode_caps & (1 << i)) + // if (devc->profile->dev_caps.mode_caps & (1 << i)) + if (supported_Demo[0].dev_caps.mode_caps & (1 << i)) l = g_slist_append(l, &sr_mode_list[i]); } @@ -242,158 +519,213 @@ static const GSList *hw_dev_mode_list(const struct sr_dev_inst *sdi) static int hw_dev_open(struct sr_dev_inst *sdi) { - //(void)sdi; - struct demo_context *const devc = sdi->priv; + int ret; + assert(sdi); + assert(sdi->priv); - if (sdi->status == SR_ST_ACTIVE) + if (sdi->status == SR_ST_ACTIVE){ return SR_OK; + } - reset_demo_device(sdi); + //扫描目录文件 + scan_dsl_file(sdi); + struct session_vdev* vdev = sdi->priv; + vdev->trig_pos = 0; + vdev->trig_time = 0; + vdev->cur_block = 0; + vdev->cur_channel = 0; + vdev->cur_probes = 0; + vdev->num_blocks = 0; + if(sdi->mode == LOGIC) + { + vdev->unit_bits = 1; + } + else + { + vdev->unit_bits = 8; + } + + //固定值 + vdev->ref_min = 1; + vdev->ref_max = 255; + + vdev->timebase = SR_NS(500); + vdev->max_timebase = MAX_TIMEBASE; + vdev->min_timebase = MIN_TIMEBASE; + + vdev->mstatus.measure_valid = TRUE; + vdev->archive = NULL; + vdev->capfile = 0; + vdev->packet_buffer = NULL; + vdev->logic_buf = NULL; sdi->status = SR_ST_ACTIVE; - if (pipe(devc->pipe_fds)) { - /* TODO: Better error message. */ - sr_err("%s: pipe() failed", __func__); - return SR_ERR; - } - devc->channel = g_io_channel_unix_new(devc->pipe_fds[0]); - g_io_channel_set_flags(devc->channel, G_IO_FLAG_NONBLOCK, NULL); - /* Set channel encoding to binary (default is UTF-8). */ - g_io_channel_set_encoding(devc->channel, NULL, NULL); - /* Make channels to unbuffered. */ - g_io_channel_set_buffered(devc->channel, FALSE); + packet_interval = g_timer_new(); - return SR_OK; + //这个可以再看下怎么改 + init_random_data(vdev); + + ret = load_virtual_device_session(sdi); + if (ret != SR_OK) + { + sr_err("%s", "Error!Load session file failed."); + return ret; + } + + return SR_OK; } static int hw_dev_close(struct sr_dev_inst *sdi) { - //(void)sdi; - struct demo_context *const devc = sdi->priv; + struct session_vdev *vdev; + int i; + struct session_packet_buffer *pack_buf; - if (sdi->status == SR_ST_ACTIVE && devc->channel) { - g_io_channel_shutdown(devc->channel, FALSE, NULL); - g_io_channel_unref(devc->channel); - devc->channel = NULL; + if (sdi && sdi->priv) + { + vdev = sdi->priv; + + if (vdev->packet_buffer != NULL){ + pack_buf = vdev->packet_buffer; + + g_safe_free(pack_buf->post_buf); + + for (i = 0; i < SESSION_MAX_CHANNEL_COUNT; i++){ + if (pack_buf->block_bufs[i] != NULL){ + g_free(pack_buf->block_bufs[i]); + pack_buf->block_bufs[i] = NULL; + } + else{ + break; + } + } + } + + g_safe_free(vdev->packet_buffer); + //数据 + g_safe_free(vdev->logic_buf); + g_safe_free(vdev->analog_buf); + g_safe_free(sdi->path); + + sdi->status = SR_ST_INACTIVE; + return SR_OK; } - sdi->status = SR_ST_INACTIVE; - return SR_OK; + return SR_ERR_CALL_STATUS; } static int dev_destroy(struct sr_dev_inst *sdi) { + assert(sdi); hw_dev_close(sdi); + sdi->path = NULL; sr_dev_inst_free(sdi); - return SR_OK; } -static int hw_cleanup(void) -{ - return 0; -} - -static unsigned int en_ch_num(const struct sr_dev_inst *sdi) -{ - GSList *l; - unsigned int channel_en_cnt = 0; - - for (l = sdi->channels; l; l = l->next) { - struct sr_channel *probe = (struct sr_channel *)l->data; - channel_en_cnt += probe->enabled; - } - - return channel_en_cnt; -} static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel *ch, const struct sr_channel_group *cg) { - (void) cg; - - struct demo_context *devc; + (void)cg; assert(sdi); assert(sdi->priv); - devc = sdi->priv; + struct session_vdev *vdev = sdi->priv; - switch (id) { - case SR_CONF_SAMPLERATE: - *data = g_variant_new_uint64(devc->cur_samplerate); - break; - case SR_CONF_LIMIT_SAMPLES: - *data = g_variant_new_uint64(devc->limit_samples_show); - break; - case SR_CONF_LIMIT_MSEC: - *data = g_variant_new_uint64(devc->limit_msec); - break; + switch (id) + { + case SR_CONF_SAMPLERATE: + *data = g_variant_new_uint64(vdev->samplerate); + break; + case SR_CONF_LIMIT_SAMPLES: + *data = g_variant_new_uint64(vdev->total_samples); + break; case SR_CONF_DEVICE_MODE: *data = g_variant_new_int16(sdi->mode); break; - case SR_CONF_TEST: - *data = g_variant_new_boolean(FALSE); + case SR_CONF_DEMO_CHANGE: + *data = g_variant_new_boolean(is_change); break; case SR_CONF_INSTANT: - *data = g_variant_new_boolean(devc->instant); + *data = g_variant_new_boolean(instant); break; case SR_CONF_PATTERN_MODE: - *data = g_variant_new_string(pattern_strings[devc->sample_generator]); - break; + if(sdi->mode == LOGIC) + *data = g_variant_new_string(pattern_strings_logic[cur_sample_generator]); + else if(sdi->mode == DSO) + *data = g_variant_new_string(pattern_strings_dso[cur_sample_generator]); + else + *data = g_variant_new_string(pattern_strings_analog[cur_sample_generator]); + break; case SR_CONF_MAX_HEIGHT: - *data = g_variant_new_string(maxHeights[devc->max_height]); + *data = g_variant_new_string(maxHeights[vdev->max_height]); break; case SR_CONF_MAX_HEIGHT_VALUE: - *data = g_variant_new_byte(devc->max_height); + *data = g_variant_new_byte(vdev->max_height); break; case SR_CONF_PROBE_OFFSET: - *data = g_variant_new_uint16(ch->offset); + if (ch) + *data = g_variant_new_uint16(ch->offset); break; case SR_CONF_PROBE_HW_OFFSET: - *data = g_variant_new_uint16(ch->hw_offset); + if (ch) + *data = g_variant_new_uint16(ch->hw_offset); break; case SR_CONF_PROBE_VDIV: - *data = g_variant_new_uint64(ch->vdiv); + if (ch) + *data = g_variant_new_uint64(ch->vdiv); break; case SR_CONF_PROBE_FACTOR: - *data = g_variant_new_uint64(ch->vfactor); + if (ch) + *data = g_variant_new_uint64(ch->vfactor); break; case SR_CONF_TIMEBASE: - *data = g_variant_new_uint64(devc->timebase); + *data = g_variant_new_uint64(vdev->timebase); break; case SR_CONF_MAX_TIMEBASE: - if (!sdi) - return SR_ERR; *data = g_variant_new_uint64(MAX_TIMEBASE); break; case SR_CONF_MIN_TIMEBASE: - if (!sdi) - return SR_ERR; *data = g_variant_new_uint64(MIN_TIMEBASE); break; case SR_CONF_PROBE_COUPLING: - *data = g_variant_new_byte(ch->coupling); + if (ch) + *data = g_variant_new_byte(ch->coupling); break; case SR_CONF_TRIGGER_VALUE: - *data = g_variant_new_byte(ch->trig_value); + if (ch) + *data = g_variant_new_byte(ch->trig_value); break; case SR_CONF_PROBE_EN: - *data = g_variant_new_boolean(ch->enabled); + if (ch) + *data = g_variant_new_boolean(ch->enabled); break; case SR_CONF_MAX_DSO_SAMPLERATE: - *data = g_variant_new_uint64(channel_modes[devc->ch_mode].max_samplerate); + *data = g_variant_new_uint64(SR_MHZ(200)); break; case SR_CONF_MAX_DSO_SAMPLELIMITS: - *data = g_variant_new_uint64(devc->profile->dev_caps.dso_depth); + *data = g_variant_new_uint64(SR_Kn(20)); break; case SR_CONF_HW_DEPTH: - *data = g_variant_new_uint64(devc->profile->dev_caps.hw_depth / channel_modes[devc->ch_mode].unit_bits); + if(sdi->mode == DSO || (sdi->mode == LOGIC && cur_sample_generator != PATTERN_RANDOM)) + { + *data = g_variant_new_uint64(vdev->total_samples); + } + else if(sdi->mode == ANALOG) + { + *data = g_variant_new_uint64(SR_MHZ(12.5)); + } + else + { + *data = g_variant_new_uint64(SR_MHZ(100)); + } break; case SR_CONF_UNIT_BITS: - *data = g_variant_new_byte(channel_modes[devc->ch_mode].unit_bits); + *data = g_variant_new_byte(vdev->unit_bits); break; case SR_CONF_PROBE_MAP_DEFAULT: if (!sdi || !ch) @@ -416,262 +748,309 @@ static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, *data = g_variant_new_double(ch->map_max); break; case SR_CONF_VLD_CH_NUM: - *data = g_variant_new_int16(channel_modes[devc->ch_mode].num); + *data = g_variant_new_int16(vdev->num_probes); break; case SR_CONF_HAVE_ZERO: - if (!sdi) - return SR_ERR; - *data = g_variant_new_boolean(devc->profile->dev_caps.feature_caps & CAPS_FEATURE_ZERO); + break; + case SR_CONF_LOAD_DECODER: + *data = g_variant_new_boolean(cur_sample_generator != PATTERN_RANDOM); + break; + case SR_CONF_REF_MIN: + *data = g_variant_new_uint32(vdev->ref_min); + break; + case SR_CONF_REF_MAX: + *data = g_variant_new_uint32(vdev->ref_max); break; default: - return SR_ERR_NA; - } + return SR_ERR_NA; + } - return SR_OK; + return SR_OK; } static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, struct sr_channel *ch, struct sr_channel_group *cg) { - (void) cg; + (void)cg; - uint16_t i; - int ret, num_probes; - const char *stropt; - uint64_t tmp_u64; - struct demo_context *devc; + struct session_vdev *vdev; + const char *stropt; + unsigned int i; assert(sdi); assert(sdi->priv); - - devc = sdi->priv; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; + vdev = sdi->priv; - if (id == SR_CONF_SAMPLERATE) { - devc->cur_samplerate = g_variant_get_uint64(data); - devc->samples_counter = 0; - devc->pre_index = 0; - sr_dbg("%s: setting samplerate to %llu", __func__, - devc->cur_samplerate); - ret = SR_OK; - } - else if (id == SR_CONF_LIMIT_SAMPLES) { - devc->limit_msec = 0; - devc->limit_samples = g_variant_get_uint64(data); - devc->limit_samples = (devc->limit_samples + 63) & ~63; - devc->limit_samples_show = devc->limit_samples; - if (sdi->mode == DSO && en_ch_num(sdi) == 1) { - devc->limit_samples /= 2; + switch (id) + { + case SR_CONF_SAMPLERATE: + vdev->samplerate = g_variant_get_uint64(data); + if(sdi->mode == LOGIC && cur_sample_generator >PATTERN_RANDOM) + { + samplerates_file[0] = vdev->samplerate; } - sr_dbg("%s: setting limit_samples to %llu", __func__, - devc->limit_samples); - ret = SR_OK; - } - else if (id == SR_CONF_LIMIT_MSEC) { - devc->limit_msec = g_variant_get_uint64(data); - devc->limit_samples = 0; - devc->limit_samples_show = devc->limit_samples; - sr_dbg("%s: setting limit_msec to %llu", __func__, - devc->limit_msec); - ret = SR_OK; - } - else if (id == SR_CONF_DEVICE_MODE) { + sr_dbg("Setting samplerate to %llu.", vdev->samplerate); + break; + case SR_CONF_LIMIT_SAMPLES: + vdev->total_samples = g_variant_get_uint64(data); + if(sdi->mode == LOGIC && cur_sample_generator >PATTERN_RANDOM) + { + samplecounts_file[0] = vdev->total_samples; + } + sr_dbg("Setting limit samples to %llu.", vdev->total_samples); + break; + case SR_CONF_LIMIT_MSEC: + break; + case SR_CONF_DEVICE_MODE: sdi->mode = g_variant_get_int16(data); - ret = SR_OK; - init_demo_device(sdi); - sr_info("%s: setting mode to %d", __func__, sdi->mode); - } - else if (id == SR_CONF_PATTERN_MODE) { + //恢复默认信号模式 + switch (sdi->mode) + { + case LOGIC: + //默认为第一个协议模式(后面添加枚举) + if("" != get_dsl_path_by_pattern_mode(sdi->mode,PATTERN_DEFAULT)) + { + cur_sample_generator = pre_sample_generator = PATTERN_DEFAULT; + sdi->path = g_strdup(get_dsl_path_by_pattern_mode(sdi->mode,PATTERN_DEFAULT)); + } + //没有第一个协议 + else + { + cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; + sdi->path = g_strdup(""); + } + break; + case DSO: + //默认为RANDOM + cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; + sdi->path = g_strdup(""); + case ANALOG: + //默认为RANDOM + cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; + sdi->path = g_strdup(""); + default: + break; + } + load_virtual_device_session(sdi); + break; + case SR_CONF_PATTERN_MODE: stropt = g_variant_get_string(data, NULL); - ret = SR_OK; - if (!strcmp(stropt, pattern_strings[PATTERN_SINE])) { - devc->sample_generator = PATTERN_SINE; - } else if (!strcmp(stropt, pattern_strings[PATTERN_SQUARE])) { - devc->sample_generator = PATTERN_SQUARE; - } else if (!strcmp(stropt, pattern_strings[PATTERN_TRIANGLE])) { - devc->sample_generator = PATTERN_TRIANGLE; - } else if (!strcmp(stropt, pattern_strings[PATTERN_SAWTOOTH])) { - devc->sample_generator = PATTERN_SAWTOOTH; - } else if (!strcmp(stropt, pattern_strings[PATTERN_RANDOM])) { - devc->sample_generator = PATTERN_RANDOM; - } else { - ret = SR_ERR; - } + pre_sample_generator= cur_sample_generator; + //字符串有效 + if(get_pattern_mode_index_by_string(sdi->mode , stropt) != PATTERN_INVALID) + { + switch (sdi->mode) + { + case LOGIC: + cur_sample_generator = get_pattern_mode_index_by_string(sdi->mode , stropt); + break; + case DSO: + cur_sample_generator = get_pattern_mode_index_by_string(sdi->mode , stropt); + break; + case ANALOG: + cur_sample_generator = get_pattern_mode_index_by_string(sdi->mode , stropt); + break; + default: + break; + } + //文件无效 + if ("" == (sdi->path = get_dsl_path_by_pattern_mode(sdi->mode,cur_sample_generator)) && + cur_sample_generator != PATTERN_RANDOM) + { + cur_sample_generator = pre_sample_generator; + } + } + //字符串无效,返回 + else + { + cur_sample_generator = pre_sample_generator; + } + + //模式发生切换,需要重新载入 + if(cur_sample_generator != pre_sample_generator) + { + is_change = TRUE; + } + sr_dbg("%s: setting pattern to %d", - __func__, devc->sample_generator); - } - else if (id == SR_CONF_MAX_HEIGHT) { + __func__, cur_sample_generator); + break; + + case SR_CONF_MAX_HEIGHT: stropt = g_variant_get_string(data, NULL); - ret = SR_OK; - for (i = 0; i < ARRAY_SIZE(maxHeights); i++) { - if (!strcmp(stropt, maxHeights[i])) { - devc->max_height = i; + for (i = 0; i < ARRAY_SIZE(maxHeights); i++) + { + if (!strcmp(stropt, maxHeights[i])) + { + vdev->max_height = i; break; } } sr_dbg("%s: setting Signal Max Height to %d", - __func__, devc->max_height); - } - else if (id == SR_CONF_INSTANT) { - devc->instant = g_variant_get_boolean(data); - sr_dbg("%s: setting INSTANT mode to %d", __func__, - devc->instant); - ret = SR_OK; - } - else if (id == SR_CONF_HORIZ_TRIGGERPOS) { - ret = SR_OK; - } - else if (id == SR_CONF_TRIGGER_HOLDOFF) { - ret = SR_OK; - } - else if (id == SR_CONF_TRIGGER_MARGIN) { - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_EN) { + __func__, vdev->max_height); + break; + case SR_CONF_PROBE_EN: ch->enabled = g_variant_get_boolean(data); - if (en_ch_num(sdi) != 0) { - devc->limit_samples_show = devc->profile->dev_caps.dso_depth / en_ch_num(sdi); + break; + case SR_CONF_PROBE_VDIV: + ch->vdiv = g_variant_get_uint64(data); + //重新读取 + if(sdi->mode == DSO) + { + if(vdev->packet_buffer) + { + vdev->packet_buffer->post_len = 0; + vdev->packet_buffer->block_read_positions[0] = 0; + vdev->packet_buffer->block_read_positions[1] = 0; + vdev->packet_buffer->block_chan_read_pos = 0; + } + vdiv_change = TRUE; } - sr_dbg("%s: setting ENABLE of channel %d to %d", __func__, - ch->index, ch->enabled); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_VDIV) { - tmp_u64 = g_variant_get_uint64(data); - ch->vdiv = tmp_u64; - sr_dbg("%s: setting VDIV of channel %d to %llu", __func__, - ch->index, ch->vdiv); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_FACTOR) { + break; + case SR_CONF_PROBE_FACTOR: ch->vfactor = g_variant_get_uint64(data); - sr_dbg("%s: setting FACTOR of channel %d to %llu", __func__, - ch->index, ch->vfactor); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_OFFSET) { + break; + case SR_CONF_PROBE_OFFSET: ch->offset = g_variant_get_uint16(data); - sr_dbg("%s: setting OFFSET of channel %d to %d", __func__, - ch->index, ch->offset); - ret = SR_OK; - } - else if (id == SR_CONF_TIMEBASE) { - devc->timebase = g_variant_get_uint64(data); - sr_dbg("%s: setting TIMEBASE to %llu", __func__, - devc->timebase); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_COUPLING) { + break; + case SR_CONF_PROBE_HW_OFFSET: + ch->hw_offset = g_variant_get_uint16(data); + break; + case SR_CONF_TIMEBASE: + vdev->timebase = g_variant_get_uint64(data); + sr_dbg("Setting timebase to %llu.", vdev->timebase); + break; + case SR_CONF_PROBE_COUPLING: ch->coupling = g_variant_get_byte(data); - sr_dbg("%s: setting AC COUPLING of channel %d to %d", __func__, - ch->index, ch->coupling); - ret = SR_OK; - } - else if (id == SR_CONF_TRIGGER_SOURCE) { - devc->trigger_source = g_variant_get_byte(data); - sr_dbg("%s: setting Trigger Source to %d", - __func__, devc->trigger_source); - ret = SR_OK; - } - else if (id == SR_CONF_TRIGGER_SLOPE) { - devc->trigger_slope = g_variant_get_byte(data); - sr_dbg("%s: setting Trigger Slope to %d", - __func__, devc->trigger_slope); - ret = SR_OK; - } - else if (id == SR_CONF_TRIGGER_VALUE) { + if(sdi->mode == ANALOG) + { + if(ch->coupling == 0) + ch->hw_offset = 178; + else + ch->hw_offset = 128; + } + else if(sdi->mode == DSO) + { + if(ch->coupling == 0) + ch->hw_offset = 178; + else + ch->hw_offset = 128; + } + break; + case SR_CONF_TRIGGER_SOURCE: + break; + case SR_CONF_TRIGGER_SLOPE: + break; + case SR_CONF_TRIGGER_VALUE: ch->trig_value = g_variant_get_byte(data); - sr_dbg("%s: setting channel %d Trigger Value to %d", - __func__, ch->index, ch->trig_value); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_MAP_DEFAULT) { + break; + case SR_CONF_PROBE_MAP_DEFAULT: ch->map_default = g_variant_get_boolean(data); if (ch->map_default) { ch->map_unit = probeMapUnits[0]; ch->map_min = -(ch->vdiv * ch->vfactor * DS_CONF_DSO_VDIVS / 2000.0); ch->map_max = ch->vdiv * ch->vfactor * DS_CONF_DSO_VDIVS / 2000.0; } - ret = SR_OK; + break; + case SR_CONF_PROBE_MAP_UNIT: + ch->map_unit = g_variant_get_string(data, NULL); + break; + case SR_CONF_PROBE_MAP_MIN: + ch->map_min = g_variant_get_double(data); + break; + case SR_CONF_PROBE_MAP_MAX: + ch->map_max = g_variant_get_double(data); + if(sdi->mode == ANALOG) + break; + case SR_CONF_NUM_BLOCKS: + vdev->num_blocks = g_variant_get_uint64(data); + sr_dbg("Setting block number to %llu.", vdev->num_blocks); + break; + case SR_CONF_CAPTURE_NUM_PROBES: + vdev->num_probes = g_variant_get_uint64(data); + break; + case SR_CONF_INSTANT: + instant = g_variant_get_boolean(data); + break; + case SR_CONF_DEMO_CHANGE: + is_change = g_variant_get_boolean(data); + break; + //初始化DEMO + case SR_CONF_DEMO_INIT: + pre_sample_generator = cur_sample_generator; + load_virtual_device_session(sdi); + default: + sr_err("Unknown capability: %d.", id); + return SR_ERR_NA; } - else if (id == SR_CONF_PROBE_MAP_UNIT) { - if (ch->map_default) - ch->map_unit = probeMapUnits[0]; - else - ch->map_unit = g_variant_get_string(data, NULL); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_MAP_MIN) { - if (ch->map_default) - ch->map_min = -(ch->vdiv * ch->vfactor * DS_CONF_DSO_VDIVS / 2000.0); - else - ch->map_min = g_variant_get_double(data); - ret = SR_OK; - } - else if (id == SR_CONF_PROBE_MAP_MAX) { - if (ch->map_default) - ch->map_max = ch->vdiv * ch->vfactor * DS_CONF_DSO_VDIVS / 2000.0; - else - ch->map_max = g_variant_get_double(data); - ret = SR_OK; - } - else { - ret = SR_ERR_NA; - } - return ret; + return SR_OK; + } static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) { - struct demo_context *devc; - GVariant *gvar; - GVariantBuilder gvb; - int i; + (void)cg; - (void)cg; - devc = sdi->priv; + GVariant *gvar; + GVariantBuilder gvb; - switch (key) { + (void)sdi; + struct session_vdev *vdev = sdi->priv; + + switch (key) + { case SR_CONF_DEVICE_OPTIONS: -// *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32, -// hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t)); *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), - hwoptions, ARRAY_SIZE(hwoptions)*sizeof(int32_t), TRUE, NULL, NULL); + hwoptions, ARRAY_SIZE(hwoptions) * sizeof(int32_t), TRUE, NULL, NULL); break; case SR_CONF_DEVICE_SESSIONS: *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), - sessions, ARRAY_SIZE(sessions)*sizeof(int32_t), TRUE, NULL, NULL); + sessions, ARRAY_SIZE(sessions) * sizeof(int32_t), TRUE, NULL, NULL); break; case SR_CONF_SAMPLERATE: - g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); - gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), - samplerates + devc->samplerates_min_index, - (devc->samplerates_max_index - devc->samplerates_min_index + 1) * sizeof(uint64_t), TRUE, NULL, NULL); + g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); + if(sdi->mode == LOGIC && cur_sample_generator != PATTERN_RANDOM) + { + gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), + samplerates_file, ARRAY_SIZE(samplerates_file) * sizeof(uint64_t), TRUE, NULL, NULL); + } + else + { + gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), + samplerates + vdev->samplerates_min_index , (vdev->samplerates_max_index - vdev->samplerates_min_index + 1) * sizeof(uint64_t), TRUE, NULL, NULL); + } g_variant_builder_add(&gvb, "{sv}", "samplerates", gvar); - *data = g_variant_builder_end(&gvb); - break; + *data = g_variant_builder_end(&gvb); + break; case SR_CONF_PATTERN_MODE: - *data = g_variant_new_strv(pattern_strings, ARRAY_SIZE(pattern_strings)); - break; + if(sdi->mode == LOGIC) + { + *data = g_variant_new_strv(pattern_strings_logic, pattern_logic_count); + } + else if (sdi->mode == DSO) + { + *data = g_variant_new_strv(pattern_strings_dso, pattern_dso_count); + } + else + { + *data = g_variant_new_strv(pattern_strings_analog, pattern_analog_count); + } + break; case SR_CONF_MAX_HEIGHT: *data = g_variant_new_strv(maxHeights, ARRAY_SIZE(maxHeights)); break; - case SR_CONF_PROBE_CONFIGS: *data = g_variant_new_from_data(G_VARIANT_TYPE("ai"), - probeOptions, ARRAY_SIZE(probeOptions)*sizeof(int32_t), TRUE, NULL, NULL); + probeOptions, ARRAY_SIZE(probeOptions) * sizeof(int32_t), TRUE, NULL, NULL); break; - case SR_CONF_PROBE_VDIV: g_variant_builder_init(&gvb, G_VARIANT_TYPE("a{sv}")); - for (i = 0; devc->profile->dev_caps.vdivs[i]; i++); gvar = g_variant_new_from_data(G_VARIANT_TYPE("at"), - devc->profile->dev_caps.vdivs, i*sizeof(uint64_t), TRUE, NULL, NULL); + vdivs10to2000, (ARRAY_SIZE(vdivs10to2000)-1) * sizeof(uint64_t), TRUE, NULL, NULL); g_variant_builder_add(&gvb, "{sv}", "vdivs", gvar); *data = g_variant_builder_end(&gvb); break; @@ -685,430 +1064,1438 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, case SR_CONF_PROBE_MAP_UNIT: *data = g_variant_new_strv(probeMapUnits, ARRAY_SIZE(probeMapUnits)); break; - default: - return SR_ERR_NA; - } + default: + return SR_ERR_ARG; + } return SR_OK; } -static void samples_generator(uint16_t *buf, uint64_t size, - const struct sr_dev_inst *sdi, - struct demo_context *devc) -{ - uint64_t i, pre0_i, pre1_i; - GSList *l; - struct sr_channel *probe; - unsigned int start_rand; - double span = 1; - const uint64_t len = ARRAY_SIZE(sinx) - 1; - const int *pre_buf; - uint16_t tmp_u16 = 0; - unsigned int ch_num = en_ch_num(sdi) ? en_ch_num(sdi) : 1; - - switch (devc->sample_generator) { - case PATTERN_SINE: /* Sine */ - pre_buf = sinx; - break; - case PATTERN_SQUARE: - pre_buf = sqrx; - break; - case PATTERN_TRIANGLE: - pre_buf = trix; - break; - case PATTERN_SAWTOOTH: - pre_buf = sawx; - break; - case PATTERN_RANDOM: - pre_buf = ranx; - break; - default: - pre_buf = sinx; - break; - } - - if (sdi->mode == LOGIC) { - for (i = 0; i < size; i++) { - //index = (i/10/g_slist_length(sdi->channels)+start_rand)%len; - //*(buf + i) = (uint16_t)(((const_dc+pre_buf[index]) << 8) + (const_dc+pre_buf[index])); - tmp_u16 = 0; - if (i < ch_num*4) - *(buf + i) = tmp_u16; - else if (i % 4 == 0) { - start_rand = rand() % (ch_num * 4); - if (start_rand == (i/4 % ch_num)) - tmp_u16 = 0xffff; - *(buf + i) = tmp_u16 ? ~*(buf + i - ch_num*4) : *(buf + i - ch_num*4); - } else { - *(buf + i) = *(buf + i - 1); - } - } - } else { - if (sdi->mode == DSO) { - if (ch_num == 1) - span = 2 * channel_modes[devc->ch_mode].max_samplerate / devc->cur_samplerate; - else - span = channel_modes[devc->ch_mode].max_samplerate / devc->cur_samplerate; - } else if (sdi->mode == ANALOG) { - span = len * 20.0 / devc->limit_samples; - } - - if (devc->pre_index == 0) { - devc->mstatus.ch0_max = 0; - devc->mstatus.ch0_min = 255; - devc->mstatus.ch1_max = 0; - devc->mstatus.ch1_min = 255; - devc->mstatus.ch0_cyc_tlen = 0; - devc->mstatus.ch0_cyc_cnt = 1; - devc->mstatus.ch1_cyc_tlen = 0; - devc->mstatus.ch1_cyc_cnt = 1; - devc->mstatus.ch0_level_valid = TRUE; - devc->mstatus.ch0_plevel = TRUE; - devc->mstatus.ch1_level_valid = TRUE; - devc->mstatus.ch1_plevel = TRUE; - } - - if (sdi->mode == DSO) - memset(buf, 0, size*sizeof(uint16_t)); - else if (sdi->mode == ANALOG) - memset(buf, 0, size*sizeof(uint16_t)); - - for (l = sdi->channels; l; l = l->next) { - start_rand = devc->pre_index * span; - probe = (struct sr_channel *)l->data; - pre0_i = devc->pre_index; - pre1_i = devc->pre_index; - for (i = 0; i < size; i++) { - if (probe->coupling == SR_DC_COUPLING) { - *(buf + i) += (uint8_t)(probe->hw_offset + (1000.0/probe->vdiv) * (pre_buf[(uint64_t)(i*span+start_rand)%len] - const_dc)) << (probe->index * 8); - } else if (probe->coupling == SR_AC_COUPLING) { - *(buf + i) += (uint8_t)(probe->hw_offset + (1000.0/probe->vdiv) * pre_buf[(uint64_t)(i*span+start_rand)%len]) << (probe->index * 8); - } else { - *(buf + i) += probe->hw_offset << (probe->index * 8); - } - - if (probe->index == 0) { - devc->mstatus.ch0_max = MAX(devc->mstatus.ch0_max, (*(buf + i) & 0x00ff)); - devc->mstatus.ch0_min = MIN(devc->mstatus.ch0_min, (*(buf + i) & 0x00ff)); - if (pre_buf[(uint64_t)(i*span+start_rand)%len] < 0 && - pre_buf[(uint64_t)((i-1)*span+start_rand)%len] > 0) { - devc->mstatus.ch0_cyc_tlen = 2*(i - pre0_i)*pow(10, 8)/channel_modes[devc->ch_mode].max_samplerate; - devc->mstatus.ch0_cyc_cnt++; - pre0_i = i; - } - } else { - devc->mstatus.ch1_max = MAX(devc->mstatus.ch1_max, ((*(buf + i) & 0xff00) >> 8)); - devc->mstatus.ch1_min = MIN(devc->mstatus.ch1_min, ((*(buf + i) & 0xff00) >> 8)); - if (pre_buf[(uint64_t)(i*span+start_rand)%len] < 0 && - pre_buf[(uint64_t)((i-1)*span+start_rand)%len] > 0) { - devc->mstatus.ch1_cyc_tlen = 2*(i - pre1_i)*pow(10, 8)/channel_modes[devc->ch_mode].max_samplerate; - devc->mstatus.ch1_cyc_cnt++; - pre1_i = i; - } - } - } - } - - for (l = sdi->channels; l; l = l->next) { - probe = (struct sr_channel *)l->data; - if (!probe->enabled) { - devc->mstatus.ch1_max = MAX(devc->mstatus.ch0_max, devc->mstatus.ch1_max); - devc->mstatus.ch1_min = MIN(devc->mstatus.ch0_min, devc->mstatus.ch1_min); - devc->mstatus.ch0_max = MAX(devc->mstatus.ch0_max, devc->mstatus.ch1_max); - devc->mstatus.ch0_min = MIN(devc->mstatus.ch0_min, devc->mstatus.ch1_min); - break; - } - } - - devc->mstatus.ch0_cyc_tlen *= devc->mstatus.ch0_cyc_cnt; - devc->mstatus.ch1_cyc_tlen *= devc->mstatus.ch1_cyc_cnt; - - devc->mstatus.ch0_high_level = devc->mstatus.ch0_max; - devc->mstatus.ch0_low_level = devc->mstatus.ch0_min; - devc->mstatus.ch1_high_level = devc->mstatus.ch1_max; - devc->mstatus.ch1_low_level = devc->mstatus.ch1_min; - devc->mstatus.ch0_cyc_llen = 0; - devc->mstatus.ch1_cyc_llen = 0; - devc->mstatus.ch0_cyc_plen = devc->mstatus.ch0_cyc_tlen / 2; - devc->mstatus.ch1_cyc_plen = devc->mstatus.ch1_cyc_tlen / 2; - devc->mstatus.ch0_cyc_rlen = devc->mstatus.ch0_cyc_tlen / 4; - devc->mstatus.ch0_cyc_flen = devc->mstatus.ch0_cyc_tlen / 4; - devc->mstatus.ch1_cyc_rlen = devc->mstatus.ch1_cyc_tlen / 4; - devc->mstatus.ch1_cyc_flen = devc->mstatus.ch1_cyc_tlen / 4; - - for (l = sdi->channels; l; l = l->next) { - probe = (struct sr_channel *)l->data; - if (probe->index == 0) { - devc->mstatus.ch0_acc_mean = (probe->coupling == SR_AC_COUPLING) ? probe->hw_offset * devc->limit_samples_show : - (devc->mstatus.ch0_max + devc->mstatus.ch0_min) / 2.0 * devc->limit_samples_show; - devc->mstatus.ch0_acc_square = (probe->coupling == SR_AC_COUPLING) ? pow((devc->mstatus.ch0_max - probe->hw_offset) * 0.707, 2) * devc->limit_samples_show : - pow((devc->mstatus.ch0_max - devc->mstatus.ch0_min) * 0.707, 2) * devc->limit_samples_show; - } else { - devc->mstatus.ch1_acc_mean = (probe->coupling == SR_AC_COUPLING) ? probe->hw_offset * devc->limit_samples_show : - (devc->mstatus.ch1_max + devc->mstatus.ch1_min) / 2.0 * devc->limit_samples_show; - devc->mstatus.ch1_acc_square = (probe->coupling == SR_AC_COUPLING) ? pow((devc->mstatus.ch1_max - probe->hw_offset) * 0.707, 2) * devc->limit_samples_show : - pow((devc->mstatus.ch1_max - devc->mstatus.ch1_min) * 0.707, 2) * devc->limit_samples_show; - } - } - - devc->mstatus.measure_valid = TRUE; - } -} - -/* Callback handling data */ -static int receive_data(int fd, int revents, const struct sr_dev_inst *sdi) -{ - struct demo_context *devc = sdi->priv; - struct sr_datafeed_packet packet; - struct sr_datafeed_logic logic; - struct sr_datafeed_dso dso; - struct sr_datafeed_analog analog; - double samples_elaspsed; - uint64_t samples_to_send = 0, sending_now; - int64_t time, elapsed; - static uint16_t last_sample = 0; - uint16_t cur_sample; - uint64_t i; - - (void)fd; - (void)revents; - - packet.status = SR_PKT_OK; - /* How many "virtual" samples should we have collected by now? */ - time = g_get_monotonic_time(); - elapsed = time - devc->starttime; - devc->starttime = time; - //expected_samplenum = ceil(elapsed / 1000000.0 * devc->cur_samplerate); - /* Of those, how many do we still have to send? */ - samples_elaspsed = elapsed / 1000000.0 * devc->cur_samplerate; - - if (devc->limit_samples) { - if (sdi->mode == DSO && !devc->instant) { - samples_to_send = ceil(samples_elaspsed); - } else if (sdi->mode == ANALOG) { - samples_to_send = ceil(samples_elaspsed); - } else { - samples_to_send = ceil(samples_elaspsed); - samples_to_send += devc->samples_not_sent; - if (samples_to_send < 64) { - devc->samples_not_sent = samples_to_send; - return TRUE; - } else - devc->samples_not_sent = samples_to_send & 63; - samples_to_send = samples_to_send & ~63; - samples_to_send = MIN(samples_to_send, - devc->limit_samples - devc->samples_counter); - } - } - - if (samples_to_send > 0 && !devc->stop) { - sending_now = MIN(samples_to_send, (sdi->mode == DSO ) ? DSO_BUFSIZE : BUFSIZE); - if (sdi->mode == DSO && !devc->instant) { - if (en_ch_num(sdi) == 1) { - devc->samples_counter += sending_now / 2; - devc->samples_counter = min(devc->samples_counter, devc->limit_samples_show / 2); - } else { - devc->samples_counter += sending_now; - devc->samples_counter = min(devc->samples_counter, devc->limit_samples_show); - } - } else { - devc->samples_counter += sending_now; - } - - if (sdi->mode == ANALOG) - samples_generator(devc->buf, sending_now*2, sdi, devc); - else if (sdi->mode == DSO) - samples_generator(devc->buf, devc->samples_counter, sdi, devc); - else - samples_generator(devc->buf, sending_now, sdi, devc); - - if (devc->trigger_stage != 0) { - for (i = 0; i < sending_now; i++) { - if (devc->trigger_edge == 0) { - if ((*(devc->buf + i) | devc->trigger_mask) == - (devc->trigger_value | devc->trigger_mask)) { - devc->trigger_stage = 0; - break; - } - } else { - cur_sample = *(devc->buf + i); - if (((last_sample & devc->trigger_edge) == - (~devc->trigger_value & devc->trigger_edge)) && - ((cur_sample | devc->trigger_mask) == - (devc->trigger_value | devc->trigger_mask)) && - ((cur_sample & devc->trigger_edge) == - (devc->trigger_value & devc->trigger_edge))) { - devc->trigger_stage = 0; - break; - } - last_sample = cur_sample; - } - } - if (devc->trigger_stage == 0) { - struct ds_trigger_pos demo_trigger_pos; - demo_trigger_pos.real_pos = i; - packet.type = SR_DF_TRIGGER; - packet.payload = &demo_trigger_pos; - ds_data_forward(sdi, &packet); - } - } - - if (devc->trigger_stage == 0){ - //samples_to_send -= sending_now; - if (sdi->mode == LOGIC) { - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - logic.length = sending_now * (channel_modes[devc->ch_mode].num >> 3); - logic.format = LA_CROSS_DATA; - logic.data = devc->buf; - } else if (sdi->mode == DSO) { - packet.type = SR_DF_DSO; - packet.payload = &dso; - dso.probes = sdi->channels; - if (devc->instant) - dso.num_samples = sending_now; - else - dso.num_samples = devc->samples_counter; - if (en_ch_num(sdi) == 1) - dso.num_samples *= 2; - dso.mq = SR_MQ_VOLTAGE; - dso.unit = SR_UNIT_VOLT; - dso.mqflags = SR_MQFLAG_AC; - dso.data = devc->buf; - }else { - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - analog.probes = sdi->channels; - analog.num_samples = sending_now; - analog.unit_bits = channel_modes[devc->ch_mode].unit_bits;; - analog.mq = SR_MQ_VOLTAGE; - analog.unit = SR_UNIT_VOLT; - analog.mqflags = SR_MQFLAG_AC; - analog.data = devc->buf; - } - - if (sdi->mode == DSO && !devc->instant) { - if ((uint64_t)dso.num_samples < devc->limit_samples_show) - devc->pre_index = 0; - else - devc->pre_index += sending_now; - } else if (sdi->mode == ANALOG) { - devc->pre_index += sending_now; - } - - ds_data_forward(sdi, &packet); - - devc->mstatus.trig_hit = (devc->trigger_stage == 0); - devc->mstatus.captured_cnt0 = devc->samples_counter; - devc->mstatus.captured_cnt1 = devc->samples_counter >> 8; - devc->mstatus.captured_cnt2 = devc->samples_counter >> 16; - devc->mstatus.captured_cnt3 = devc->samples_counter >> 32; - } - } - - if ((sdi->mode == LOGIC || devc->instant) && devc->limit_samples && - devc->samples_counter >= devc->limit_samples) { - sr_dbg("Requested number of samples reached."); - hw_dev_acquisition_stop(sdi, NULL); - return TRUE; - } - - return TRUE; -} - static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, void *cb_data) { - struct demo_context *const devc = sdi->priv; + + (void)cb_data; - (void)cb_data; + struct session_vdev *vdev; + struct sr_datafeed_packet packet; + int ret; + GSList *l; + struct sr_channel *probe; - if (sdi->status != SR_ST_ACTIVE) - return SR_ERR_DEV_CLOSED; + assert(sdi); + assert(sdi->priv); - //devc->cb_data = cb_data; - devc->samples_counter = 0; - devc->pre_index = 0; - devc->mstatus.captured_cnt0 = 0; - devc->mstatus.captured_cnt1 = 0; - devc->mstatus.captured_cnt2 = 0; - devc->mstatus.captured_cnt3 = 0; - devc->stop = FALSE; - devc->samples_not_sent = 0; - devc->trigger_stage = 0; + vdev = sdi->priv; + vdev->enabled_probes = 0; + packet.status = SR_PKT_OK; - /* - * Setting two channels connected by a pipe is a remnant from when the - * demo driver generated data in a thread, and collected and sent the - * data in the main program loop. - * They are kept here because it provides a convenient way of setting - * up a timeout-based polling mechanism. - */ + vdev->cur_block = 0; + vdev->cur_channel = 0; - sr_session_source_add_channel(devc->channel, G_IO_IN | G_IO_ERR, - 50, receive_data, sdi); + //在启动前检查文件是否有效 + if(cur_sample_generator != PATTERN_RANDOM) + { + if (vdev->archive != NULL) + { + sr_err("history archive is not closed."); + } - /* Send header packet to the session bus. */ - //std_session_send_df_header(cb_data, LOG_PREFIX); - std_session_send_df_header(sdi, LOG_PREFIX); + sr_dbg("Opening archive file %s", sdi->path); - if (!(devc->buf = g_try_malloc(((sdi->mode == DSO ) ? DSO_BUFSIZE : (sdi->mode == ANALOG ) ? 2*BUFSIZE : BUFSIZE)*sizeof(uint16_t)))) { - sr_err("buf for receive_data malloc failed."); - return FALSE; + vdev->archive = unzOpen64(sdi->path); + + if (NULL == vdev->archive) + { + sr_err("Failed to open session file '%s': " + "zip error %d\n", + sdi->path, ret); + return SR_ERR; + } } - /* We use this timestamp to decide how many more samples to send. */ - devc->starttime = g_get_monotonic_time(); + if (sdi->mode == LOGIC) + vdev->cur_channel = 0; + else + vdev->cur_channel = vdev->num_probes - 1; - return SR_OK; + for (l = sdi->channels; l; l = l->next) + { + probe = l->data; + if (probe->enabled) + vdev->enabled_probes++; + } + + /* Send header packet to the session bus. */ + std_session_send_df_header(sdi, LOG_PREFIX); + + /* Send trigger packet to the session bus */ + if (vdev->trig_pos != 0) + { + struct ds_trigger_pos session_trigger; + if (sdi->mode == DSO) + session_trigger.real_pos = vdev->trig_pos * vdev->enabled_probes / vdev->num_probes; + else + session_trigger.real_pos = vdev->trig_pos; + packet.type = SR_DF_TRIGGER; + packet.payload = &session_trigger; + ds_data_forward(sdi, &packet); + } + + if(sdi->mode == LOGIC) + { + enabled_probe_num = 0; + for(GSList *l = sdi->channels; l; l = l->next) + { + probe = (struct sr_channel *)l->data; + if(probe->enabled) + { + enabled_probe_num++; + } + } + is_first = TRUE; + post_data_len = 0; + uint64_t post_date_per_second = vdev->samplerate / 8 ; + packet_len = post_date_per_second / 22; + packet_len = floor(packet_len/8)*8; + packet_time = 1/(double)22; + if(cur_sample_generator == PATTERN_RANDOM) + { + sr_session_source_add(-1, 0, 0, receive_data_logic, sdi); + } + else + { + sr_session_source_add(-1, 0, 0, receive_data_logic_decoder, sdi); + } + } + else if(sdi->mode == DSO) + { + is_first = TRUE; + vdiv_change = TRUE; + packet_time = 1/(double)200; + sr_session_source_add(-1, 0, 0, receive_data_dso, sdi); + } + else if(sdi->mode == ANALOG) + { + is_first = TRUE; + gdouble total_time = vdev->total_samples/vdev->samplerate; + uint64_t post_date_per_second = vdev->total_samples / total_time *2; + packet_len = post_date_per_second / 22; + + if(packet_len <= 1) + { + packet_len = 2; + packet_time = post_date_per_second / 2; + packet_time = 1/packet_time; + } + else + { + if (packet_len %2 != 0) + { + packet_len += 1; + } + packet_time = 1/(double)22; + } + + vdev->analog_buf_len = 0; + vdev->analog_read_pos = 0; + + sr_session_source_add(-1, 0, 0, receive_data_analog, sdi); + } + + return SR_OK; } static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data) { - (void)cb_data; - - struct demo_context *const devc = sdi->priv; + struct session_vdev *vdev = sdi->priv; struct sr_datafeed_packet packet; - if (devc->stop) - return SR_OK; - - sr_dbg("Stopping acquisition."); - - devc->stop = TRUE; - - sr_session_source_remove_channel(devc->channel); - - g_free(devc->buf); - - /* Send last packet. */ - packet.type = SR_DF_END; packet.status = SR_PKT_OK; - ds_data_forward(sdi, &packet); - return SR_OK; + if(sdi->mode != LOGIC) + { + packet.type = SR_DF_END; + ds_data_forward(sdi, &packet); + close_archive(vdev); + } + + return SR_OK; } static int hw_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg) { (void)prg; - if (sdi) { - struct demo_context *const devc = sdi->priv; - *status = devc->mstatus; + struct session_vdev *vdev; + + if (sdi) + { + vdev = sdi->priv; + *status = vdev->mstatus; return SR_OK; - } else { + } + else + { return SR_ERR; } } +static int receive_data_logic(int fd, int revents, const struct sr_dev_inst *sdi) +{ + struct session_vdev *vdev = NULL; + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; + + int ret; + char file_name[32]; + int channel; + int ch_index, malloc_chan_index; + struct session_packet_buffer *pack_buffer; + unz_file_info64 fileInfo; + char szFilePath[15]; + int bToEnd; + int read_chan_index; + int chan_num; + uint8_t *p_wr; + uint8_t *p_rd; + int byte_align; + int dir_index; + int bCheckFile; + const int file_max_channel_count = 128; + + assert(sdi); + assert(sdi->priv); + + (void)fd; + (void)revents; + + sr_detail("Feed chunk."); + + ret = 0; + bToEnd = 0; + packet.status = SR_PKT_OK; + + vdev = sdi->priv; + + assert(vdev->unit_bits > 0); + + chan_num = enabled_probe_num; + byte_align = sdi->mode == LOGIC ? 8 : 1; + + if (chan_num < 1){ + sr_err("%s: channel count < 1.", __func__); + return SR_ERR_ARG; + } + if (chan_num > SESSION_MAX_CHANNEL_COUNT){ + sr_err("%s: channel count is to big.", __func__); + return SR_ERR_ARG; + } + + g_timer_start(packet_interval); + + if (vdev->packet_buffer == NULL){ + vdev->cur_block = 0; + + vdev->packet_buffer = g_try_malloc0(sizeof(struct session_packet_buffer)); + if (vdev->packet_buffer == NULL){ + sr_err("%s: vdev->packet_buffer malloc failed", __func__); + return SR_ERR_MALLOC; + } + } + pack_buffer = vdev->packet_buffer; + + + // Make packet. + read_chan_index = 0; + dir_index = 0; + + if(post_data_len >= vdev->total_samples/8) + { + bToEnd = 1; + } + + if(!bToEnd) + { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.format = LA_CROSS_DATA; + logic.index = 0; + logic.order = 0; + logic.length = chan_num * packet_len; + //防止越界 + post_data_len += logic.length / enabled_probe_num; + if(post_data_len >= vdev->total_samples/8) + { + int last_packet_len = post_data_len - (logic.length / enabled_probe_num); + last_packet_len = (vdev->total_samples/8) - last_packet_len; + logic.length = last_packet_len * enabled_probe_num; + } + //注意传输缓冲 + uint64_t random = vdev->logic_buf_len - logic.length; + random = abs(rand()) %random; + logic.data = vdev->logic_buf + random; + + gdouble packet_elapsed = g_timer_elapsed(packet_interval, NULL); + gdouble waittime = packet_time - packet_elapsed; + if(waittime > 0) + { + g_usleep(waittime*1000000); + } + ds_data_forward(sdi, &packet); + pack_buffer->post_len = 0; + } + + if (bToEnd || revents == -1) + { + packet.type = SR_DF_END; + ds_data_forward(sdi, &packet); + sr_session_source_remove(-1); + } + + return TRUE; +} + +static int receive_data_logic_decoder(int fd, int revents, const struct sr_dev_inst *sdi) +{ + struct session_vdev *vdev = NULL; + struct sr_datafeed_packet packet; + struct sr_datafeed_logic logic; + struct sr_datafeed_dso dso; + + int ret; + char file_name[32]; + int channel; + int ch_index, malloc_chan_index; + struct session_packet_buffer *pack_buffer; + unz_file_info64 fileInfo; + char szFilePath[15]; + int bToEnd; + int read_chan_index; + int chan_num; + uint8_t *p_wr; + uint8_t *p_rd; + int byte_align; + int dir_index; + int bCheckFile; + const int file_max_channel_count = 128; + + assert(sdi); + assert(sdi->priv); + + (void)fd; + (void)revents; + + sr_detail("Feed chunk."); + + ret = 0; + bToEnd = 0; + packet.status = SR_PKT_OK; + + vdev = sdi->priv; + + assert(vdev->unit_bits > 0); + assert(vdev->archive); + + chan_num = enabled_probe_num; + byte_align = sdi->mode == LOGIC ? 8 : 1; + + if (chan_num < 1){ + sr_err("%s: channel count < 1.", __func__); + return SR_ERR_ARG; + } + if (chan_num > SESSION_MAX_CHANNEL_COUNT){ + sr_err("%s: channel count is to big.", __func__); + return SR_ERR_ARG; + } + + g_timer_start(packet_interval); + + // Make buffer + if (vdev->packet_buffer == NULL){ + vdev->cur_block = 0; + + vdev->packet_buffer = g_try_malloc0(sizeof(struct session_packet_buffer)); + if (vdev->packet_buffer == NULL){ + sr_err("%s: vdev->packet_buffer malloc failed", __func__); + return SR_ERR_MALLOC; + } + + for (ch_index = 0; ch_index <= chan_num; ch_index++){ + vdev->packet_buffer->block_bufs[ch_index] = NULL; + vdev->packet_buffer->block_read_positions[ch_index] = 0; + } + + vdev->packet_buffer->post_buf_len = chan_num * packet_len; + + vdev->packet_buffer->post_buf = g_try_malloc0(vdev->packet_buffer->post_buf_len + 1); + if (vdev->packet_buffer->post_buf == NULL){ + sr_err("%s: vdev->packet_buffer->post_buf malloc failed", __func__); + return SR_ERR_MALLOC; + } + + pack_buffer = vdev->packet_buffer; + pack_buffer->post_len; + pack_buffer->block_buf_len = 0; + pack_buffer->block_data_len = 0; + pack_buffer->block_chan_read_pos = 0; + } + pack_buffer = vdev->packet_buffer; + + //传输块长度需要更新 + if(pack_buffer->post_buf_len != chan_num * packet_len) + { + pack_buffer->post_buf_len = chan_num * packet_len; + if(pack_buffer->post_buf != NULL) + { + g_free(pack_buffer->post_buf); + } + + pack_buffer->post_buf = g_try_malloc0(pack_buffer->post_buf_len); + if (pack_buffer->post_buf == NULL) + { + sr_err("%s: pack_buffer->post_buf malloc failed", __func__); + return SR_ERR_MALLOC; + } + + pack_buffer->post_len = 0; + } + + // Make packet. + read_chan_index = 0; + dir_index = 0; + + while (pack_buffer->post_len < pack_buffer->post_buf_len) + { + if (pack_buffer->block_chan_read_pos >= pack_buffer->block_data_len) + { + if(vdev->cur_block >= vdev->num_blocks){ + bToEnd = 1; + break; + } + + for (ch_index = 0; ch_index < chan_num; ch_index++) + { + bCheckFile = 0; + + while (1) + { + snprintf(file_name, sizeof(file_name)-1, "L-%d/%d", dir_index++, vdev->cur_block); + + if (unzLocateFile(vdev->archive, file_name, 0) == UNZ_OK){ + bCheckFile = 1; + break; + } + else if (dir_index > file_max_channel_count){ + break; + } + } + + if (!bCheckFile) + { + sr_err("cant't locate zip inner file:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + if (unzGetCurrentFileInfo64(vdev->archive, &fileInfo, szFilePath, + sizeof(szFilePath), NULL, 0, NULL, 0) != UNZ_OK) + { + sr_err("%s: unzGetCurrentFileInfo64 error.", __func__); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + if (ch_index == 0){ + pack_buffer->block_data_len = fileInfo.uncompressed_size; + + if (pack_buffer->block_data_len > pack_buffer->block_buf_len) + { + for (malloc_chan_index = 0; malloc_chan_index < chan_num; malloc_chan_index++){ + // Release the old buffer. + if (pack_buffer->block_bufs[malloc_chan_index] != NULL){ + g_free(pack_buffer->block_bufs[malloc_chan_index]); + pack_buffer->block_bufs[malloc_chan_index] = NULL; + } + + pack_buffer->block_bufs[malloc_chan_index] = g_try_malloc0(pack_buffer->block_data_len + 1); + if (pack_buffer->block_bufs[malloc_chan_index] == NULL){ + sr_err("%s: block buffer malloc failed", __func__); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + pack_buffer->block_buf_len = pack_buffer->block_data_len; + } + } + } + else + { + if (pack_buffer->block_data_len != fileInfo.uncompressed_size){ + sr_err("The block size is not coincident:%s", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + } + + // Read the data to buffer. + if (unzOpenCurrentFile(vdev->archive) != UNZ_OK) + { + sr_err("cant't open zip inner file:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + ret = unzReadCurrentFile(vdev->archive, pack_buffer->block_bufs[ch_index], pack_buffer->block_data_len); + if (-1 == ret) + { + sr_err("read zip inner file error:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + unzCloseCurrentFile(vdev->archive); + pack_buffer->block_read_positions[ch_index] = 0; // Reset the read position. + } + vdev->cur_block++; + pack_buffer->block_chan_read_pos = 0; + } + + p_wr = (uint8_t*)pack_buffer->post_buf + pack_buffer->post_len; + p_rd = (uint8_t*)pack_buffer->block_bufs[read_chan_index] + pack_buffer->block_read_positions[read_chan_index]; + *p_wr = *p_rd; + + pack_buffer->post_len++; + pack_buffer->block_read_positions[read_chan_index]++; + + if (pack_buffer->block_read_positions[read_chan_index] % byte_align == 0 + || pack_buffer->block_read_positions[read_chan_index] == pack_buffer->block_data_len) + { + read_chan_index++; + + if (pack_buffer->block_read_positions[read_chan_index] == pack_buffer->block_data_len){ + sr_info("Block read end."); + if (vdev->cur_block < vdev->num_blocks){ + sr_err("%s", "The block data is not align."); + break; + } + } + + // Each channel's data is ready. + if (read_chan_index == chan_num){ + read_chan_index = 0; + pack_buffer->block_chan_read_pos += byte_align; + } + } + } + + if (pack_buffer->post_len >= byte_align * chan_num) + { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + logic.format = LA_CROSS_DATA; + logic.index = 0; + logic.order = 0; + logic.length = pack_buffer->post_len; + post_data_len += logic.length / enabled_probe_num; + if(post_data_len >= vdev->total_samples/8) + { + int last_packet_len = post_data_len - (logic.length / enabled_probe_num); + last_packet_len = (vdev->total_samples/8) - last_packet_len; + logic.length = last_packet_len * enabled_probe_num; + } + logic.data = pack_buffer->post_buf; + + gdouble packet_elapsed = g_timer_elapsed(packet_interval, NULL); + gdouble waittime = packet_time - packet_elapsed; + if(waittime > 0){ + g_usleep(waittime*1000000); + } + + ds_data_forward(sdi, &packet); + pack_buffer->post_len = 0; + } + + if (bToEnd || revents == -1) + { + packet.type = SR_DF_END; + ds_data_forward(sdi, &packet); + sr_session_source_remove(-1); + close_archive(vdev); + } + + return TRUE; +} + +static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) +{ + struct session_vdev *vdev = NULL; + struct sr_datafeed_packet packet; + struct sr_datafeed_dso dso; + struct sr_channel *probe; + + int ret; + char file_name[32]; + int channel; + int ch_index, malloc_chan_index; + struct session_packet_buffer *pack_buffer; + unz_file_info64 fileInfo; + char szFilePath[15]; + int bToEnd; + int read_chan_index; + int chan_num; + uint8_t *p_wr; + uint8_t *p_rd; + int byte_align; + int dir_index; + int bCheckFile; + const int file_max_channel_count = 128; + + uint16_t tem; + uint8_t val = 0; + uint64_t vdiv; + + assert(sdi); + assert(sdi->priv); + + (void)fd; + (void)revents; + + sr_detail("Feed chunk."); + + ret = 0; + bToEnd = 0; + packet.status = SR_PKT_OK; + + vdev = sdi->priv; + + assert(vdev->unit_bits > 0); + if(cur_sample_generator != PATTERN_RANDOM) + { + assert(vdev->archive); + } + + chan_num = vdev->num_probes; + byte_align = sdi->mode == LOGIC ? 8 : 1; + + if (chan_num < 1){ + sr_err("%s: channel count < 1.", __func__); + return SR_ERR_ARG; + } + if (chan_num > SESSION_MAX_CHANNEL_COUNT){ + sr_err("%s: channel count is to big.", __func__); + return SR_ERR_ARG; + } + + // Make buffer + if (vdev->packet_buffer == NULL){ + vdev->cur_block = 0; + + vdev->packet_buffer = g_try_malloc0(sizeof(struct session_packet_buffer)); + if (vdev->packet_buffer == NULL){ + sr_err("%s: vdev->packet_buffer malloc failed", __func__); + return SR_ERR_MALLOC; + } + + //初始化读取块 + for (ch_index = 0; ch_index <= chan_num; ch_index++){ + vdev->packet_buffer->block_bufs[ch_index] = NULL; + vdev->packet_buffer->block_read_positions[ch_index] = 0; + } + + vdev->packet_buffer->post_buf_len = chan_num * 10000; + + //不需要+1 + vdev->packet_buffer->post_buf = g_try_malloc0(vdev->packet_buffer->post_buf_len); + if (vdev->packet_buffer->post_buf == NULL){ + sr_err("%s: vdev->packet_buffer->post_buf malloc failed", __func__); + return SR_ERR_MALLOC; + } + + pack_buffer = vdev->packet_buffer; + pack_buffer->post_len; + pack_buffer->block_buf_len = 0; + pack_buffer->block_data_len = 0; + pack_buffer->block_chan_read_pos = 0; + } + pack_buffer = vdev->packet_buffer; + + //重新分配缓冲 + if(pack_buffer->post_buf_len != chan_num * 10000) + { + vdev->packet_buffer->post_buf_len = chan_num * 10000; + if(pack_buffer->post_buf != NULL) + { + g_free(pack_buffer->post_buf); + } + pack_buffer->post_buf = g_try_malloc0(pack_buffer->post_buf_len); + if (pack_buffer->post_buf == NULL) + { + sr_err("%s: pack_buffer->post_buf malloc failed", __func__); + return SR_ERR_MALLOC; + } + + pack_buffer->post_len = 0; + } + + // Make packet. + read_chan_index = 0; + dir_index = 0; + + if(vdiv_change) + { + //随机 + if(cur_sample_generator == PATTERN_RANDOM) + { + //波形不太理想 + for(int i = 0 ; i < pack_buffer->post_buf_len ;i++) + { + *(uint8_t*)(pack_buffer->post_buf + i) = rand()%40 +110; + } + pack_buffer->post_len = pack_buffer->post_buf_len; + } + //文件 + else + { + while (pack_buffer->post_len < pack_buffer->post_buf_len) + { + if (pack_buffer->block_chan_read_pos >= pack_buffer->block_data_len) + { + if (vdev->cur_block >= vdev->num_blocks){ + bToEnd = 1; + break; + } + + for (ch_index = 0; ch_index < chan_num; ch_index++) + { + bCheckFile = 0; + + while (1) + { + if (sdi->mode == LOGIC) + snprintf(file_name, sizeof(file_name)-1, "L-%d/%d", dir_index++, vdev->cur_block); + else if (sdi->mode == DSO) + snprintf(file_name, sizeof(file_name)-1, "O-%d/0", dir_index++); + + if (unzLocateFile(vdev->archive, file_name, 0) == UNZ_OK){ + bCheckFile = 1; + break; + } + else if (dir_index > file_max_channel_count){ + break; + } + } + + if (!bCheckFile) + { + sr_err("cant't locate zip inner file:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + if (unzGetCurrentFileInfo64(vdev->archive, &fileInfo, szFilePath, + sizeof(szFilePath), NULL, 0, NULL, 0) != UNZ_OK) + { + sr_err("%s: unzGetCurrentFileInfo64 error.", __func__); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + if (ch_index == 0){ + pack_buffer->block_data_len = fileInfo.uncompressed_size; + + if (pack_buffer->block_data_len > pack_buffer->block_buf_len) + { + for (malloc_chan_index = 0; malloc_chan_index < chan_num; malloc_chan_index++){ + // Release the old buffer. + if (pack_buffer->block_bufs[malloc_chan_index] != NULL){ + g_free(pack_buffer->block_bufs[malloc_chan_index]); + pack_buffer->block_bufs[malloc_chan_index] = NULL; + } + + pack_buffer->block_bufs[malloc_chan_index] = g_try_malloc0(pack_buffer->block_data_len + 1); + if (pack_buffer->block_bufs[malloc_chan_index] == NULL){ + sr_err("%s: block buffer malloc failed", __func__); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + pack_buffer->block_buf_len = pack_buffer->block_data_len; + } + } + } + else + { + if (pack_buffer->block_data_len != fileInfo.uncompressed_size){ + sr_err("The block size is not coincident:%s", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + } + + // Read the data to buffer. + if (unzOpenCurrentFile(vdev->archive) != UNZ_OK) + { + sr_err("cant't open zip inner file:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + ret = unzReadCurrentFile(vdev->archive, pack_buffer->block_bufs[ch_index], pack_buffer->block_data_len); + if (-1 == ret) + { + sr_err("read zip inner file error:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + unzCloseCurrentFile(vdev->archive); + pack_buffer->block_read_positions[ch_index] = 0; // Reset the read position. + } + vdev->cur_block++; + pack_buffer->block_chan_read_pos = 0; + } + + p_wr = (uint8_t*)pack_buffer->post_buf + pack_buffer->post_len; + p_rd = (uint8_t*)pack_buffer->block_bufs[read_chan_index] + pack_buffer->block_read_positions[read_chan_index]; + *p_wr = *p_rd; + + pack_buffer->post_len++; + pack_buffer->block_read_positions[read_chan_index]++; + + if (pack_buffer->block_read_positions[read_chan_index] % byte_align == 0 + || pack_buffer->block_read_positions[read_chan_index] == pack_buffer->block_data_len) + { + read_chan_index++; + + if (pack_buffer->block_read_positions[read_chan_index] == pack_buffer->block_data_len){ + sr_info("Block read end."); + if (vdev->cur_block < vdev->num_blocks){ + sr_err("%s", "The block data is not align."); + break; + } + } + + // Each channel's data is ready. + if (read_chan_index == chan_num){ + read_chan_index = 0; + pack_buffer->block_chan_read_pos += byte_align; + } + } + } + } + + //处理vdiv + for(int i = 0 ; i < pack_buffer->post_buf_len; i++) + { + tem = 0; + if(i % 2 == 0) + probe = g_slist_nth(sdi->channels, 0)->data; + else + probe = g_slist_nth(sdi->channels, 1)->data; + vdiv = probe->vdiv; + uint8_t temp_val = *((uint8_t*)pack_buffer->post_buf + i); + if(temp_val>128) + { + val = temp_val - 128; + tem = val * 1000 / vdiv; + tem = 128 + tem; + if(tem >= 255) + temp_val = 255; + else + temp_val = tem; + } + else if(temp_val < 128 && temp_val != 0) + { + val = 128 - temp_val; + tem = val * 1000 / vdiv; + tem = 128 - tem; + + if(tem == 0) + temp_val = 1; + else + temp_val = tem; + } + *((uint8_t*)pack_buffer->post_buf + i) = temp_val; + } + + vdiv_change = FALSE; + } + + //数据循环 + uint8_t top0; + uint8_t top1; + if(cur_sample_generator == PATTERN_RANDOM) + { + top0 = *((uint8_t*)pack_buffer->post_buf + pack_buffer->post_buf_len -2); + top1 = *((uint8_t*)pack_buffer->post_buf + pack_buffer->post_buf_len -1); + } + else + { + top0 = *((uint8_t*)pack_buffer->post_buf + 198); + top1 = *((uint8_t*)pack_buffer->post_buf + 199); + } + + + for(int i = pack_buffer->post_len -1; i > 1; i -= 2){ + *((uint8_t*)pack_buffer->post_buf + i) = *((uint8_t*)pack_buffer->post_buf + i - 2); + } + + for(int i = pack_buffer->post_len -2; i > 0; i -= 2){ + *((uint8_t*)pack_buffer->post_buf + i) = *((uint8_t*)pack_buffer->post_buf + i - 2); + } + + *(uint8_t*)pack_buffer->post_buf = top0; + *((uint8_t*)pack_buffer->post_buf + 1)= top1; + + + if (pack_buffer->post_len >= byte_align * chan_num) + { + packet.type = SR_DF_DSO; + packet.payload = &dso; + dso.probes = sdi->channels; + dso.mq = SR_MQ_VOLTAGE; + dso.unit = SR_UNIT_VOLT; + dso.mqflags = SR_MQFLAG_AC; + dso.num_samples = pack_buffer->post_len / chan_num; + dso.data = pack_buffer->post_buf; + + gdouble packet_elapsed = g_timer_elapsed(packet_interval, NULL); + gdouble waittime = packet_time - packet_elapsed; + if(waittime > 0){ + g_usleep(waittime*1000000); + } + g_timer_start(packet_interval); + // Send data back. + ds_data_forward(sdi, &packet); + } + + if(instant) + { + bToEnd = 1; + instant = FALSE; + } + + if (bToEnd || revents == -1) + { + packet.type = SR_DF_END; + ds_data_forward(sdi, &packet); + sr_session_source_remove(-1); + if(cur_sample_generator != PATTERN_RANDOM) + { + close_archive(vdev);; + } + } + + return TRUE; +} + + +//修改称原有版本(读取文件) +static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sdi) +{ + struct session_vdev *vdev = sdi->priv; + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + struct sr_channel *probe = NULL; + + char file_name[32]; + int ret; + + assert(sdi); + assert(sdi->priv); + + (void)fd; + (void)revents; + + sr_detail("Feed chunk."); + + packet.status = SR_PKT_OK; + + assert(vdev->unit_bits > 0); + + g_timer_start(packet_interval); + + if(is_first) + { + void* analog_data = g_try_malloc0(206); + if(analog_data == NULL) + { + sr_err("%s:cant' malloc",__func__); + return SR_ERR_MALLOC; + } + //随机数据 + if(cur_sample_generator == PATTERN_RANDOM) + { + for(int i = 0 ; i < 206 ;i++) + { + *(uint8_t*)(analog_data + i) = rand()%40 +110; + } + } + //文件 + else + { + snprintf(file_name, sizeof(file_name)-1, "%s-%d/%d", "A", + 0, 0); + + if (unzLocateFile(vdev->archive, file_name, 0) != UNZ_OK) + { + sr_err("cant't locate zip inner file:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + if (unzOpenCurrentFile(vdev->archive) != UNZ_OK) + { + sr_err("cant't open zip inner file:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + + ret = unzReadCurrentFile(vdev->archive, analog_data, 206); + if (-1 == ret) + { + sr_err("read zip inner file error:\"%s\"", file_name); + send_error_packet(sdi, vdev, &packet); + return FALSE; + } + } + + //计算放大后数据 + gdouble rate = 103 / (gdouble)2048 ; + uint64_t total_buf_len = rate * vdev->total_samples; + + if(total_buf_len % 103 != 0) + { + total_buf_len = total_buf_len / 103 * 103; + } + total_buf_len = total_buf_len * 2; + + if(vdev->analog_buf != NULL) + { + g_free(vdev->analog_buf); + vdev->analog_buf = NULL; + } + vdev->analog_buf = (g_try_malloc0(total_buf_len)); + if (vdev->analog_buf == NULL) + { + return SR_ERR_MALLOC; + } + vdev->analog_buf_len = total_buf_len; + uint64_t per_block_after_expend = total_buf_len /206; + + //根据vdiv对电压进行放大 + probe = g_slist_nth(sdi->channels, 0)->data; + uint64_t p0_vdiv = probe->vdiv; + probe = g_slist_nth(sdi->channels, 1)->data; + uint64_t p1_vdiv = probe->vdiv; + uint64_t vdiv; + uint8_t val = 0; + uint16_t tem; + uint64_t cur_l = 0; + for(int i = 0 ; i < 206;i++) + { + if(i == 0 || i % 2 == 0) + vdiv = p0_vdiv; + else + vdiv = p1_vdiv; + tem = 0; + + uint8_t temp_value = *((uint8_t*)analog_data + i); + + if(temp_value > 128){ + val = temp_value - 128; + tem = val * 1000 / vdiv; + tem = 128 + tem; + if(tem >= 255) + temp_value = 255; + else + temp_value = tem; + } + else if(temp_value < 128 && temp_value != 0) + { + val = 128 - temp_value; + tem = val * 1000 / vdiv; + tem = 128 - tem; + if(tem == 0) + temp_value = 1; + else + temp_value = tem; + } + + //对数据进行拓展 + for(int j = 0 ; j analog_buf + cur_l,temp_value,1); + } + } + is_first = FALSE; + } + + //注意区分发送数据额缓冲数据 + void* buf; + if(vdev->analog_read_pos + packet_len >= vdev->analog_buf_len - 1 ) + { + buf = g_try_malloc0(packet_len); + uint64_t back_len = vdev->analog_buf_len - vdev->analog_read_pos; + for (int i = 0; i < back_len; i++) + { + uint8_t temp_val = *((uint8_t*)vdev->analog_buf + vdev->analog_read_pos + i); + memset(buf + i,temp_val,1); + } + + uint64_t front_len = packet_len - back_len; + for (int i = 0; i < front_len; i++) + { + uint8_t temp_val = *((uint8_t*)vdev->analog_buf + i); + memset(buf + back_len + i,temp_val,1); + } + vdev->analog_read_pos = front_len; + } + else + { + buf = (uint8_t*) vdev->analog_buf + vdev->analog_read_pos; + vdev->analog_read_pos += packet_len; + } + + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + analog.probes = sdi->channels; + analog.num_samples = packet_len / vdev->num_probes; + analog.unit_bits = vdev->unit_bits; + analog.mq = SR_MQ_VOLTAGE; + analog.unit = SR_UNIT_VOLT; + analog.mqflags = SR_MQFLAG_AC; + analog.data = buf; + + gdouble packet_elapsed = g_timer_elapsed(packet_interval, NULL); + gdouble waittime = packet_time - packet_elapsed; + if(waittime > 0){ + g_usleep(waittime*1000000); + } + + ds_data_forward(sdi, &packet); + + return TRUE; +} + +static void send_error_packet(const struct sr_dev_inst *cb_sdi, struct session_vdev *vdev, struct sr_datafeed_packet *packet) +{ + packet->type = SR_DF_END; + packet->status = SR_PKT_SOURCE_ERROR; + ds_data_forward(cb_sdi, packet); + sr_session_source_remove(-1); + close_archive(vdev); +} + + +static int close_archive(struct session_vdev *vdev) +{ + if(cur_sample_generator != PATTERN_RANDOM) + { + assert(vdev->archive); + + // close current inner file + if (vdev->capfile) + { + unzCloseCurrentFile(vdev->archive); + vdev->capfile = 0; + } + + int ret = unzClose(vdev->archive); + if (ret != UNZ_OK) + { + sr_err("close zip archive error!"); + } + + vdev->archive = NULL; + } + + return SR_OK; +} + +static int load_virtual_device_session(struct sr_dev_inst *sdi) +{ + GKeyFile *kf; + unzFile archive = NULL; + char szFilePath[15]; + unz_file_info64 fileInfo; + + struct sr_channel *probe; + int ret, devcnt, i, j; + uint16_t probenum; + uint64_t tmp_u64, total_probes, enabled_probes; + uint16_t p; + int64_t tmp_64; + char **sections, **keys, *metafile, *val; + char probename[SR_MAX_PROBENAME_LEN + 1]; + int mode = LOGIC; + int channel_type = SR_CHANNEL_LOGIC; + double tmp_double; + int version = 1; + + assert(sdi); + //如果不是random要检查文件 + if (cur_sample_generator != PATTERN_RANDOM) + { + assert(sdi->path); + } + + //逻辑分析仪初始化(RANDOM) + if (sdi->mode == LOGIC && cur_sample_generator == PATTERN_RANDOM) + { + sdi->driver->config_set(SR_CONF_SAMPLERATE, + g_variant_new_uint64(SR_MHZ(1)), sdi, NULL, NULL); + sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, + g_variant_new_uint64(SR_MHZ(1)), sdi, NULL, NULL); + sr_dev_probes_free(sdi); + sdi->driver->config_set(SR_CONF_CAPTURE_NUM_PROBES, + g_variant_new_uint64(16), sdi, NULL, NULL); + sdi->driver->config_set(SR_CONF_NUM_BLOCKS, + g_variant_new_uint64(6), sdi, NULL, NULL); + + char* probe_val; + for (int i = 0; i < 16; i++) + { + probe_val = probe_names[i]; + if (!(probe = sr_channel_new(i, SR_CHANNEL_LOGIC, TRUE, probe_val))) + { + sr_err("%s: create channel failed", __func__); + sr_dev_inst_free(sdi); + return SR_ERR; + } + + sdi->channels = g_slist_append(sdi->channels, probe); + } + adjust_samplerate(sdi); + } + //示波器初始化 + else if(sdi->mode == DSO) + { + sdi->driver->config_set(SR_CONF_SAMPLERATE, + g_variant_new_uint64(SR_MHZ(100)), sdi, NULL, NULL); + sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, + g_variant_new_uint64(SR_KHZ(10)), sdi, NULL, NULL); + sr_dev_probes_free(sdi); + sdi->driver->config_set(SR_CONF_CAPTURE_NUM_PROBES, + g_variant_new_uint64(2), sdi, NULL, NULL); + sdi->driver->config_set(SR_CONF_NUM_BLOCKS, + g_variant_new_uint64(1), sdi, NULL, NULL); + char* probe_val; + for (int i = 0; i < 2; i++) + { + probe_val = probe_names[i]; + if (!(probe = sr_channel_new(i, SR_CHANNEL_DSO, TRUE, probe_val))) + { + sr_err("%s: create channel failed", __func__); + sr_dev_inst_free(sdi); + return SR_ERR; + } + probe->enabled = TRUE; + probe->coupling = 1; + probe->vdiv = 1000; + probe->vfactor = 1000; + probe->hw_offset = 128; + probe->offset = 128; + probe->trig_value = 0.5; + sdi->channels = g_slist_append(sdi->channels, probe); + } + adjust_samplerate(sdi); + } + //数据记录仪初始化 + else if(sdi->mode == ANALOG) + { + sdi->driver->config_set(SR_CONF_SAMPLERATE, + g_variant_new_uint64(SR_MHZ(1)), sdi, NULL, NULL); + sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, + g_variant_new_uint64(SR_MHZ(1)), sdi, NULL, NULL); + sr_dev_probes_free(sdi); + sdi->driver->config_set(SR_CONF_CAPTURE_NUM_PROBES, + g_variant_new_uint64(2), sdi, NULL, NULL); + sdi->driver->config_set(SR_CONF_NUM_BLOCKS, + g_variant_new_uint64(1), sdi, NULL, NULL); + char* probe_val; + for (int i = 0; i < 2; i++) + { + probe_val = probe_names[i]; + if (!(probe = sr_channel_new(i, SR_CHANNEL_ANALOG, TRUE, probe_val))) + { + sr_err("%s: create channel failed", __func__); + sr_dev_inst_free(sdi); + return SR_ERR; + } + + //做一个用于通道初始化的函数 + probe->enabled = TRUE; + probe->bits = 8; + probe->vdiv = 1000; + probe->hw_offset = 128; + probe->offset = 128; + probe->coupling = 1; + probe->vfactor = 1; + probe->trig_value = 128; + probe->map_default = TRUE; + probe->map_unit = "V"; + probe->map_min = -(probe->vdiv * probe->vfactor * DS_CONF_DSO_VDIVS / 2000.0); + probe->map_max = probe->vdiv * probe->vfactor * DS_CONF_DSO_VDIVS / 2000.0; + + sdi->channels = g_slist_append(sdi->channels, probe); + } + adjust_samplerate(sdi); + } + //协议文件初始化 + else + { + archive = unzOpen64(sdi->path); + if (NULL == archive) + { + sr_err("%s: Load zip file error.", __func__); + return SR_ERR; + } + if (unzLocateFile(archive, "header", 0) != UNZ_OK) + { + unzClose(archive); + sr_err("%s: unzLocateFile error.", __func__); + return SR_ERR; + } + if (unzGetCurrentFileInfo64(archive, &fileInfo, szFilePath, + sizeof(szFilePath), NULL, 0, NULL, 0) != UNZ_OK) + { + unzClose(archive); + sr_err("%s: unzGetCurrentFileInfo64 error.", __func__); + return SR_ERR; + } + if (unzOpenCurrentFile(archive) != UNZ_OK) + { + sr_err("%s: Cant't open zip inner file.", __func__); + unzClose(archive); + return SR_ERR; + } + + if (!(metafile = g_try_malloc(fileInfo.uncompressed_size))) + { + sr_err("%s: metafile malloc failed", __func__); + return SR_ERR_MALLOC; + } + + unzReadCurrentFile(archive, metafile, fileInfo.uncompressed_size); + unzCloseCurrentFile(archive); + + if (unzClose(archive) != UNZ_OK) + { + sr_err("%s: Close zip archive error.", __func__); + return SR_ERR; + } + archive = NULL; + + kf = g_key_file_new(); + if (!g_key_file_load_from_data(kf, metafile, fileInfo.uncompressed_size, 0, NULL)) + { + sr_err("Failed to parse metadata."); + return SR_ERR; + } + + devcnt = 0; + sections = g_key_file_get_groups(kf, NULL); + + for (i = 0; sections[i]; i++) + { + if (!strcmp(sections[i], "version")) + { + keys = g_key_file_get_keys(kf, sections[i], NULL, NULL); + for (j = 0; keys[j]; j++) + { + val = g_key_file_get_string(kf, sections[i], keys[j], NULL); + if (!strcmp(keys[j], "version")) + { + version = strtoull(val, NULL, 10); + sr_info("The 'header' file format version:%d", version); + } + } + } + + if (!strncmp(sections[i], "header", 6)) + { + enabled_probes = total_probes = 0; + keys = g_key_file_get_keys(kf, sections[i], NULL, NULL); + + for (j = 0; keys[j]; j++) + { + val = g_key_file_get_string(kf, sections[i], keys[j], NULL); + sr_info("keys:%s , val:%s", keys[j],val); + + if (!strcmp(keys[j], "device mode")) + { + mode = strtoull(val, NULL, 10); + } + else if (!strcmp(keys[j], "samplerate")) + { + sr_parse_sizestring(val, &tmp_u64); + sdi->driver->config_set(SR_CONF_SAMPLERATE, + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); + } + else if (!strcmp(keys[j], "total samples")) + { + tmp_u64 = strtoull(val, NULL, 10); + sdi->driver->config_set(SR_CONF_LIMIT_SAMPLES, + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); + + } + else if (!strcmp(keys[j], "total blocks")) + { + tmp_u64 = strtoull(val, NULL, 10); + sdi->driver->config_set(SR_CONF_NUM_BLOCKS, + g_variant_new_uint64(tmp_u64), sdi, NULL, NULL); + } + else if (!strcmp(keys[j], "total probes")) + { + sr_dev_probes_free(sdi); + total_probes = strtoull(val, NULL, 10); + sdi->driver->config_set(SR_CONF_CAPTURE_NUM_PROBES, + g_variant_new_uint64(total_probes), sdi, NULL, NULL); + } + else if (!strncmp(keys[j], "probe", 5)) + { + enabled_probes++; + tmp_u64 = strtoul(keys[j] + 5, NULL, 10); + channel_type = (mode == DSO) ? SR_CHANNEL_DSO : (mode == ANALOG) ? SR_CHANNEL_ANALOG + : SR_CHANNEL_LOGIC; + if (!(probe = sr_channel_new(tmp_u64, channel_type, TRUE, val))) + { + sr_err("%s: create channel failed", __func__); + sr_dev_inst_free(sdi); + return SR_ERR; + } + + sdi->channels = g_slist_append(sdi->channels, probe); + } + } + adjust_samplerate(sdi); + g_strfreev(keys); + } + devcnt++; + } + + g_strfreev(sections); + g_key_file_free(kf); + g_free(metafile); + } + + return SR_OK; +} + + SR_PRIV struct sr_dev_driver demo_driver_info = { .name = "virtual-demo", .longname = "Demo driver and pattern generator", .api_version = 1, .driver_type = DRIVER_TYPE_DEMO, .init = hw_init, - .cleanup = hw_cleanup, + .cleanup = NULL, .scan = hw_scan, .dev_mode_list = hw_dev_mode_list, .config_get = config_get, diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index da1a2774..2c36d32c 100644 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -23,24 +23,112 @@ #include #include "../../libsigrok-internal.h" +#include +//原版导入方式**(channel_modes冲突) +#include"../DSL/dsl.h" -/* Supported patterns which we can generate */ +/*修改*/ + +//信号模式 enum DEMO_PATTERN { - PATTERN_SINE = 0, - PATTERN_SQUARE = 1, - PATTERN_TRIANGLE = 2, - PATTERN_SAWTOOTH = 3, - PATTERN_RANDOM = 4, + PATTERN_INVALID = -1, + PATTERN_RANDOM = 0, + PATTERN_DEFAULT = 1, }; -static const char *pattern_strings[] = { - "Sine", - "Square", - "Triangle", - "Sawtooth", - "Random", +static char *pattern_strings_logic[100] = {"RANDOM"}; +static char *pattern_strings_dso[100] = {"RANDOM"}; +static char *pattern_strings_analog[100] = {"RANDOM"}; +static int pattern_logic_count = 1; +static int pattern_dso_count= 1; +static int pattern_analog_count= 1; + +//协议采样率、总样本数列表 +static uint64_t samplerates_file[1]; +static uint64_t samplecounts_file[1]; +//定时器 +static GTimer *packet_interval = NULL; +//首次开启 +static gboolean is_first = TRUE; +static gboolean is_change = FALSE; +//总共启用通道数(LOGIC会使用) +static int enabled_probe_num; +//包长度、包时间、总传输包长度 +static uint64_t packet_len; +static gdouble packet_time; +static uint64_t post_data_len; +//文件路径 +extern char DS_RES_PATH[500]; +//示波器垂直分辨率变化 +static gboolean vdiv_change; +//立即 +static gboolean instant = FALSE; +//路径 +extern char DS_RES_PATH[500]; +//信号模式(起始一样) +uint8_t cur_sample_generator; +uint8_t pre_sample_generator; + +struct session_packet_buffer; + +struct session_vdev +{ + int version; + unzFile archive; // zip document + int capfile; // current inner file open status + + uint16_t samplerates_min_index; + uint16_t samplerates_max_index; + //逻辑分析仪随机数据 + void *logic_buf; + uint64_t logic_buf_len; + //数据记录仪周期数据 + void *analog_buf; + uint64_t analog_buf_len; + uint64_t analog_read_pos; + //示波器周期数据 + + int cur_channel; + int cur_block; + int num_blocks; + uint64_t samplerate; + uint64_t total_samples; + int64_t trig_time; + uint64_t trig_pos; + int cur_probes; + int num_probes; + int enabled_probes; + uint64_t timebase; + uint64_t max_timebase; + uint64_t min_timebase; + uint8_t unit_bits; + uint32_t ref_min; + uint32_t ref_max; + uint8_t max_height; + struct sr_status mstatus; + struct session_packet_buffer *packet_buffer; }; + + +#define SESSION_MAX_CHANNEL_COUNT 512 + +struct session_packet_buffer +{ + void *post_buf; + uint64_t post_buf_len; + uint64_t post_len; + + uint64_t block_buf_len; + uint64_t block_chan_read_pos; + uint64_t block_data_len; + void *block_bufs[SESSION_MAX_CHANNEL_COUNT]; + uint64_t block_read_positions[SESSION_MAX_CHANNEL_COUNT]; +}; + + +/*修改*/ + struct DEMO_caps { uint64_t mode_caps; uint64_t feature_caps; @@ -63,22 +151,10 @@ struct DEMO_profile { struct DEMO_caps dev_caps; }; -static const uint64_t vdivs10to2000[] = { - SR_mV(10), - SR_mV(20), - SR_mV(50), - SR_mV(100), - SR_mV(200), - SR_mV(500), - SR_V(1), - SR_V(2), - 0, -}; - enum DEMO_CHANNEL_ID { DEMO_LOGIC100x16 = 0, - DEMO_ANALOG10x2, - DEMO_DSO200x2, + DEMO_ANALOG10x2 = 1 , + DEMO_DSO200x2 = 2, }; struct DEMO_channels { @@ -227,6 +303,15 @@ static const int32_t probeOptions[] = { SR_CONF_PROBE_MAP_MAX, }; +static const int32_t probeSessions[] = { + SR_CONF_PROBE_COUPLING, + SR_CONF_PROBE_VDIV, + SR_CONF_PROBE_MAP_DEFAULT, + SR_CONF_PROBE_MAP_UNIT, + SR_CONF_PROBE_MAP_MIN, + SR_CONF_PROBE_MAP_MAX, +}; + static const uint8_t probeCoupling[] = { SR_DC_COUPLING, SR_AC_COUPLING, @@ -258,8 +343,8 @@ static const struct DEMO_profile supported_Demo[] = { 0, vdivs10to2000, 0, - DEMO_LOGIC100x16, - PATTERN_SINE, + DEMO_LOGIC100x16, + PATTERN_RANDOM, SR_NS(500)} }, @@ -332,4 +417,62 @@ static const int ranx[] = { -41, 36, -8, 46, 47, -34, 28, -39, 7, -32, 38, -27, 28, -3, -8, 43, -37, -24, 6, 3, }; +static int init_pattern_mode_list(); + +static int get_pattern_mode_index_by_string(uint8_t device_mode , const char* str); + +static int scan_dsl_file(struct sr_dev_inst *sdi); + +static char* get_dsl_path_by_pattern_mode(uint8_t device_mode ,uint8_t pattern_mode); + +static void adjust_samplerate(struct sr_dev_inst *sdi); + +static int init_random_data(struct session_vdev * vdev); + +static int hw_init(struct sr_context *sr_ctx); + +static GSList *hw_scan(GSList *options); + +static const GSList *hw_dev_mode_list(const struct sr_dev_inst *sdi); + +static int hw_dev_open(struct sr_dev_inst *sdi); + +static int hw_dev_close(struct sr_dev_inst *sdi); + +static int dev_destroy(struct sr_dev_inst *sdi); + + +static int config_get(int id, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel *ch, + const struct sr_channel_group *cg); + +static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, + struct sr_channel *ch, + struct sr_channel_group *cg); + +static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg); + +static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, + void *cb_data); + +static int hw_dev_acquisition_stop(const struct sr_dev_inst *sdi, void *cb_data); + +static int hw_dev_status_get(const struct sr_dev_inst *sdi, struct sr_status *status, gboolean prg); + +static int load_virtual_device_session(struct sr_dev_inst *sdi); + +static int receive_data_logic(int fd, int revents, const struct sr_dev_inst *sdi); + +static int receive_data_logic_decoder(int fd, int revents, const struct sr_dev_inst *sdi); + +static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi); + +static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sdi); + +static void send_error_packet(const struct sr_dev_inst *cb_sdi, struct session_vdev *vdev, struct sr_datafeed_packet *packet); + +static int close_archive(struct session_vdev *vdev); + + #endif diff --git a/libsigrok4DSL/lib_main.c b/libsigrok4DSL/lib_main.c index c8805bcf..f5181438 100644 --- a/libsigrok4DSL/lib_main.c +++ b/libsigrok4DSL/lib_main.c @@ -647,7 +647,8 @@ SR_API int ds_get_actived_device_info(struct ds_device_full_info *fill_info) strncpy(p->driver_name, dev->driver->name, sizeof(p->driver_name) - 1); } - if (dev->dev_type == DEV_TYPE_FILELOG && dev->path != NULL){ + //demo paht + if ((dev->dev_type == DEV_TYPE_FILELOG || dev->dev_type == DEV_TYPE_DEMO) && dev->path != NULL){ strncpy(p->path, dev->path, sizeof(p->path) - 1); } ret = SR_OK; diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index 5565623b..90fa7d23 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -1033,6 +1033,13 @@ enum sr_config_option_id /** The device supports setting the number of data blocks. */ SR_CONF_NUM_BLOCKS = 30104, + /** demo **/ + SR_CONF_LOAD_DECODER = 30105, + + SR_CONF_DEMO_INIT = 30106, + + SR_CONF_DEMO_CHANGE = 30107, + /*--- Acquisition modes ---------------------------------------------*/ /** From 8a7bece0cabc2ea9839b0b2d3e75fa6f80dc8e08 Mon Sep 17 00:00:00 2001 From: yunyaobaihong <896458252@qq.com> Date: Thu, 4 May 2023 10:55:04 +0800 Subject: [PATCH 2/4] demo --- libsigrok4DSL/hardware/demo/demo.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index cf979eb5..013116f8 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -94,7 +94,7 @@ static int init_pattern_mode_list() { if(pattern_strings_dso[i] != NULL) { - g_free(pattern_strings_dso[i]);阿 + g_free(pattern_strings_dso[i]); pattern_strings_dso[i] =NULL; } } @@ -1977,10 +1977,10 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) packet.type = SR_DF_END; ds_data_forward(sdi, &packet); sr_session_source_remove(-1); - if(cur_sample_generator != PATTERN_RANDOM) - { - close_archive(vdev);; - } +// if(cur_sample_generator != PATTERN_RANDOM) +// { +// close_archive(vdev); +// } } return TRUE; From 907421f57ff92a8943d7f7ed1a1cc8b5a7aecbfd Mon Sep 17 00:00:00 2001 From: yunyaobaihong <896458252@qq.com> Date: Thu, 4 May 2023 13:57:29 +0800 Subject: [PATCH 3/4] dso loop --- libsigrok4DSL/hardware/demo/demo.c | 68 ++++++++++++++++++++---------- libsigrok4DSL/hardware/demo/demo.h | 1 + 2 files changed, 47 insertions(+), 22 deletions(-) diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index 013116f8..218c65c3 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -562,6 +562,7 @@ static int hw_dev_open(struct sr_dev_inst *sdi) sdi->status = SR_ST_ACTIVE; packet_interval = g_timer_new(); + run_time = g_timer_new(); //这个可以再看下怎么改 init_random_data(vdev); @@ -608,6 +609,10 @@ static int hw_dev_close(struct sr_dev_inst *sdi) g_safe_free(vdev->analog_buf); g_safe_free(sdi->path); + //不释放也可以? + // g_timer_destroy(packet_interval); + // g_timer_destroy(run_time); + sdi->status = SR_ST_INACTIVE; return SR_OK; } @@ -920,6 +925,8 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, break; case SR_CONF_TIMEBASE: vdev->timebase = g_variant_get_uint64(data); + if(sdi->mode == DSO) + g_timer_start(run_time); sr_dbg("Setting timebase to %llu.", vdev->timebase); break; case SR_CONF_PROBE_COUPLING: @@ -1174,6 +1181,7 @@ static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, is_first = TRUE; vdiv_change = TRUE; packet_time = 1/(double)200; + g_timer_start(run_time); sr_session_source_add(-1, 0, 0, receive_data_dso, sdi); } else if(sdi->mode == ANALOG) @@ -1197,9 +1205,11 @@ static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, } packet_time = 1/(double)22; } + vdev->analog_buf_len = 0; vdev->analog_read_pos = 0; + g_timer_start(run_time); sr_session_source_add(-1, 0, 0, receive_data_analog, sdi); } @@ -1918,32 +1928,46 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) vdiv_change = FALSE; } - //数据循环 - uint8_t top0; - uint8_t top1; - if(cur_sample_generator == PATTERN_RANDOM) - { - top0 = *((uint8_t*)pack_buffer->post_buf + pack_buffer->post_buf_len -2); - top1 = *((uint8_t*)pack_buffer->post_buf + pack_buffer->post_buf_len -1); - } - else - { - top0 = *((uint8_t*)pack_buffer->post_buf + 198); - top1 = *((uint8_t*)pack_buffer->post_buf + 199); - } + //计算时间 + gdouble total_time = vdev->timebase /(gdouble)SR_SEC(1)*(gdouble)10; + gdouble total_time_elapsed = g_timer_elapsed(run_time, NULL); + if (total_time_elapsed < total_time && !instant) + { + gdouble percent = total_time_elapsed / total_time; + int buf_len = percent* 20000; + if(buf_len %2 != 0) + buf_len -=1; + pack_buffer->post_len = buf_len; + } + else + { + //数据循环 + uint8_t top0; + uint8_t top1; + if(cur_sample_generator == PATTERN_RANDOM) + { + top0 = *((uint8_t*)pack_buffer->post_buf + pack_buffer->post_buf_len -2); + top1 = *((uint8_t*)pack_buffer->post_buf + pack_buffer->post_buf_len -1); + } + else + { + top0 = *((uint8_t*)pack_buffer->post_buf + 198); + top1 = *((uint8_t*)pack_buffer->post_buf + 199); + } - for(int i = pack_buffer->post_len -1; i > 1; i -= 2){ - *((uint8_t*)pack_buffer->post_buf + i) = *((uint8_t*)pack_buffer->post_buf + i - 2); - } + for(int i = pack_buffer->post_len -1; i > 1; i -= 2){ + *((uint8_t*)pack_buffer->post_buf + i) = *((uint8_t*)pack_buffer->post_buf + i - 2); + } - for(int i = pack_buffer->post_len -2; i > 0; i -= 2){ - *((uint8_t*)pack_buffer->post_buf + i) = *((uint8_t*)pack_buffer->post_buf + i - 2); - } - - *(uint8_t*)pack_buffer->post_buf = top0; - *((uint8_t*)pack_buffer->post_buf + 1)= top1; + for(int i = pack_buffer->post_len -2; i > 0; i -= 2){ + *((uint8_t*)pack_buffer->post_buf + i) = *((uint8_t*)pack_buffer->post_buf + i - 2); + } + *(uint8_t*)pack_buffer->post_buf = top0; + *((uint8_t*)pack_buffer->post_buf + 1)= top1; + pack_buffer->post_len = 20000; + } if (pack_buffer->post_len >= byte_align * chan_num) { diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index 2c36d32c..6073711a 100644 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -48,6 +48,7 @@ static uint64_t samplerates_file[1]; static uint64_t samplecounts_file[1]; //定时器 static GTimer *packet_interval = NULL; +static GTimer *run_time = NULL; //首次开启 static gboolean is_first = TRUE; static gboolean is_change = FALSE; From 776a18661b921cbc218ec07411cfb64776dfae73 Mon Sep 17 00:00:00 2001 From: yunyaobaihong <896458252@qq.com> Date: Fri, 5 May 2023 09:57:41 +0800 Subject: [PATCH 4/4] DEMO --- DSView/pv/mainwindow.cpp | 105 +++++++-------- DSView/pv/mainwindow.h | 6 +- DSView/pv/sigsession.cpp | 35 +---- DSView/pv/sigsession.h | 3 +- libsigrok4DSL/hardware/demo/demo.c | 207 ++++++++++++++--------------- libsigrok4DSL/hardware/demo/demo.h | 38 +++--- libsigrok4DSL/lib_main.c | 1 - libsigrok4DSL/libsigrok.h | 1 - 8 files changed, 173 insertions(+), 223 deletions(-) diff --git a/DSView/pv/mainwindow.cpp b/DSView/pv/mainwindow.cpp index b155c593..959ae6af 100644 --- a/DSView/pv/mainwindow.cpp +++ b/DSView/pv/mainwindow.cpp @@ -116,8 +116,7 @@ namespace pv _is_auto_switch_device = false; _is_save_confirm_msg = false; - _demo_load_decoder = TRUE; - _demo_auto_start = FALSE; + _pattern_mode = "RANDOM"; setup_ui(); @@ -1677,11 +1676,6 @@ namespace pv break; case DSV_MSG_START_COLLECT_WORK: - /*demo下逻辑分析仪采集一次后,设置自动采集*/ - if (_device_agent->is_demo() && _device_agent->get_work_mode() == LOGIC) - { - _demo_auto_start = TRUE; - } update_toolbar_view_status(); _view->on_state_changed(false); _protocol_widget->update_view_status(); @@ -1721,8 +1715,6 @@ namespace pv if (_device_agent->is_hardware()) { - /*切换到硬件设备,取消demo的自动采集*/ - _demo_auto_start = FALSE; _session->on_load_config_end(); } @@ -1732,8 +1724,6 @@ namespace pv if (_device_agent->is_file()) { - /*切换到硬件设备,取消demo的自动采集(目前使用gboolean类型需要includeligsigork)*/ - _demo_auto_start = FALSE; check_session_file_version(); bool bDoneDecoder = false; @@ -1750,19 +1740,25 @@ namespace pv if (_device_agent->is_demo()) { - /*demo下逻辑分析仪如果信号模式不为RANDOM,导入解码器*/ if(_device_agent->get_work_mode() == LOGIC) { - GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_LOAD_DECODER); + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_PATTERN_MODE); if(gvar != NULL) { - gboolean load_decoder = g_variant_get_boolean(gvar); - if(load_decoder) + _pattern_mode = g_variant_get_string(gvar,NULL); + g_variant_unref(gvar); + } + + _protocol_widget->del_all_protocol(); + if(_device_agent->get_work_mode() == LOGIC) + { + _view->auto_set_max_scale(); + + if(_pattern_mode != "RANDOM") { - //加载解码器 StoreSession ss(_session); QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); - ss.load_decoders(_protocol_widget, deArray); + ss.load_decoders(_protocol_widget, deArray); } } } @@ -1797,20 +1793,21 @@ namespace pv if(_device_agent->is_demo()) { - /*demo下逻辑分析仪如果信号模式不为RANDOM,导入解码器*/ + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_PATTERN_MODE); + if(gvar != NULL) + { + _pattern_mode = g_variant_get_string(gvar,NULL); + g_variant_unref(gvar); + } _protocol_widget->del_all_protocol(); + if(_device_agent->get_work_mode() == LOGIC) { - GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_LOAD_DECODER); - if(gvar != NULL) + if(_pattern_mode != "RANDOM") { - gboolean load_decoder = g_variant_get_boolean(gvar); - if(load_decoder) - { - StoreSession ss(_session); - QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); - ss.load_decoders(_protocol_widget, deArray); - } + StoreSession ss(_session); + QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); + ss.load_decoders(_protocol_widget, deArray); } } } @@ -1895,48 +1892,46 @@ namespace pv break; case DSV_MSG_END_DEVICE_OPTIONS: - if(_device_agent->is_demo()) + if(_device_agent->is_demo() &&_device_agent->get_work_mode() == LOGIC) { - /*信号模式发生修改,更新界面*/ - GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_DEMO_CHANGE); + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_PATTERN_MODE); if(gvar != NULL) { - gboolean pattern_change = g_variant_get_boolean(gvar); - if(pattern_change) + std::string pattern_mode = g_variant_get_string(gvar,NULL); + g_variant_unref(gvar); + if(pattern_mode != _pattern_mode) { - reset_all_view(); - load_device_config(); + _pattern_mode = pattern_mode; + _device_agent->set_config(NULL,NULL,SR_CONF_DEMO_INIT,g_variant_new_boolean(TRUE)); + _device_agent->update(); + + _session->init_signals(); update_toolbar_view_status(); - _device_agent->set_config(NULL,NULL,SR_CONF_DEMO_CHANGE,g_variant_new_boolean(FALSE)); - } - } + _sampling_bar->update_sample_rate_list(); - /*demo下逻辑分析仪如果信号模式不为RANDOM,导入解码器*/ - _protocol_widget->del_all_protocol(); - if(_device_agent->get_work_mode() == LOGIC) - { - _view->auto_set_max_scale(); - - GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_LOAD_DECODER); - if(gvar != NULL) - { - gboolean load_decoder = g_variant_get_boolean(gvar); - if(load_decoder) + _protocol_widget->del_all_protocol(); + + if(_pattern_mode != "RANDOM") { StoreSession ss(_session); QJsonArray deArray = get_decoder_json_from_file(_device_agent->path()); - ss.load_decoders(_protocol_widget, deArray); + ss.load_decoders(_protocol_widget, deArray); + _session->start_capture(false); } } - - /*demo下逻辑分析仪执行一次采集后,切换信号模式自动采集*/ - if(_demo_auto_start) - { - _session->start_capture(true); - } } } break; + case DSV_MSG_BEGIN_DEVICE_OPTIONS: + if(_device_agent->is_demo()) + { + GVariant *gvar = _device_agent->get_config(NULL,NULL,SR_CONF_PATTERN_MODE); + if(gvar != NULL) + { + _pattern_mode = g_variant_get_string(gvar,NULL); + g_variant_unref(gvar); + } + } } } diff --git a/DSView/pv/mainwindow.h b/DSView/pv/mainwindow.h index eafdc6c3..15affc4c 100644 --- a/DSView/pv/mainwindow.h +++ b/DSView/pv/mainwindow.h @@ -33,9 +33,6 @@ #include #include -//没有gboolean类型? -#include "libsigrok.h" - class QAction; class QMenuBar; class QMenu; @@ -217,8 +214,7 @@ private: bool _is_auto_switch_device; high_resolution_clock::time_point _last_key_press_time; bool _is_save_confirm_msg; - gboolean _demo_load_decoder; - gboolean _demo_auto_start; + std::string _pattern_mode; int _key_value; bool _key_vaild; diff --git a/DSView/pv/sigsession.cpp b/DSView/pv/sigsession.cpp index 157efa01..ff69aa94 100644 --- a/DSView/pv/sigsession.cpp +++ b/DSView/pv/sigsession.cpp @@ -758,7 +758,10 @@ namespace pv std::vector sigs; unsigned int logic_probe_count = 0; unsigned int dso_probe_count = 0; - unsigned int analog_probe_count = 0; + unsigned int analog_probe_count = 0; + + set_cur_snap_samplerate(_device_agent.get_sample_rate()); + set_cur_samplelimits(_device_agent.get_sample_limit()); // Detect what data types we will receive if (_device_agent.have_instance()) @@ -841,6 +844,9 @@ namespace pv int dso_chan_num = 0; int all_chann_num = 0; + set_cur_snap_samplerate(_device_agent.get_sample_rate()); + set_cur_samplelimits(_device_agent.get_sample_limit()); + // Make the logic probe list for (GSList *l = _device_agent.get_channels(); l; l = l->next) { @@ -1950,31 +1956,6 @@ namespace pv switch (msg) { case DSV_MSG_DEVICE_OPTIONS_UPDATED: - if(_device_agent.is_demo()) - { - GVariant *gvar = _device_agent.get_config(NULL,NULL,SR_CONF_DEMO_CHANGE); - if(gvar != NULL) - { - gboolean pattern_change = g_variant_get_boolean(gvar); - if(pattern_change) - { - /*底层重置工作参数*/ - _device_agent.set_config(NULL,NULL,SR_CONF_DEMO_INIT,g_variant_new_boolean(TRUE)); - - _device_agent.update(); - - clear_all_decoder(); - - _capture_data->clear(); - _view_data->clear(); - _capture_data = _view_data; - - init_signals(); - set_cur_snap_samplerate(_device_agent.get_sample_rate()); - set_cur_samplelimits(_device_agent.get_sample_limit()); - } - } - } reload(); break; @@ -2094,7 +2075,6 @@ namespace pv // Nonthing. } - //** bool SigSession::switch_work_mode(int mode) { assert(!_is_working); @@ -2103,7 +2083,6 @@ namespace pv if (cur_mode != mode) { GVariant *val = g_variant_new_int16(mode); - /*底层重置工作参数*/ _device_agent.set_config(NULL, NULL, SR_CONF_DEVICE_MODE, val); if (cur_mode == LOGIC){ diff --git a/DSView/pv/sigsession.h b/DSView/pv/sigsession.h index 27fc55b4..a00a1259 100644 --- a/DSView/pv/sigsession.h +++ b/DSView/pv/sigsession.h @@ -410,6 +410,7 @@ public: } void on_load_config_end(); + void init_signals(); private: void set_cur_samplelimits(uint64_t samplelimits); @@ -446,7 +447,7 @@ private: void capture_init(); void nodata_timeout(); void feed_timeout(); - void init_signals(); + void clear_decode_result(); void attach_data_to_signal(SessionData *data); diff --git a/libsigrok4DSL/hardware/demo/demo.c b/libsigrok4DSL/hardware/demo/demo.c index 218c65c3..137b2882 100644 --- a/libsigrok4DSL/hardware/demo/demo.c +++ b/libsigrok4DSL/hardware/demo/demo.c @@ -41,7 +41,7 @@ /* Message logging helpers with subsystem-specific prefix string. */ -#undef LOG_PREFIX +#undef LOG_PREFIX #define LOG_PREFIX "demo: " /* The size of chunks to send through the session bus. */ @@ -114,7 +114,7 @@ static int init_pattern_mode_list() static int get_pattern_mode_index_by_string(uint8_t device_mode , const char* str) { - int index = PATTERN_INVALID, + int index = PATTERN_INVALID, i = PATTERN_RANDOM; if (device_mode == LOGIC) { @@ -269,13 +269,13 @@ static int scan_dsl_file(struct sr_dev_inst *sdi) get_mode = TRUE; break; } - } + } } if (get_mode) { break; } - + } if(mode == LOGIC) @@ -319,7 +319,6 @@ static int scan_dsl_file(struct sr_dev_inst *sdi) } g_dir_close(dir); - //至少有一个协议文件,则设置第一个文件为默认 if (logic_index > 1) { cur_sample_generator = pre_sample_generator = PATTERN_DEFAULT; @@ -336,7 +335,6 @@ static int scan_dsl_file(struct sr_dev_inst *sdi) } } -//通过信号模式索引获取文件名 static char* get_dsl_path_by_pattern_mode(uint8_t device_mode , uint8_t pattern_mode) { unzFile archive = NULL; @@ -372,10 +370,9 @@ static char* get_dsl_path_by_pattern_mode(uint8_t device_mode , uint8_t pattern_ } strcat(str,".dsl"); } - + if(pattern_mode != PATTERN_RANDOM) { - //检查文件是否有效 archive = unzOpen64(str); if (NULL != archive) { @@ -431,7 +428,6 @@ static void adjust_samplerate(struct sr_dev_inst *sdi) } -//初始化random数据 static int init_random_data(struct session_vdev * vdev) { uint8_t random_val; @@ -439,7 +435,7 @@ static int init_random_data(struct session_vdev * vdev) { g_free(vdev->logic_buf); } - if(!(vdev->logic_buf = g_try_malloc0(SR_MB(10)))) + if(!(vdev->logic_buf = g_try_malloc0(SR_MB(10)))) { return SR_ERR; } @@ -467,13 +463,13 @@ static int hw_init(struct sr_context *sr_ctx) static GSList *hw_scan(GSList *options) { - struct sr_dev_inst *sdi; + struct sr_dev_inst *sdi; struct session_vdev *vdev; - GSList *devices; + GSList *devices; char str[500]; - (void)options; - devices = NULL; + (void)options; + devices = NULL; sr_info("%s", "Scan demo device."); @@ -484,22 +480,22 @@ static GSList *hw_scan(GSList *options) return SR_ERR_MALLOC; } - sdi = sr_dev_inst_new(LOGIC, SR_ST_INACTIVE, + sdi = sr_dev_inst_new(LOGIC, SR_ST_INACTIVE, supported_Demo[0].vendor, - supported_Demo[0].model, + supported_Demo[0].model, supported_Demo[0].model_version); - if (!sdi) { + if (!sdi) { g_free(vdev); sr_err("Device instance creation failed."); - return NULL; - } + return NULL; + } sdi->priv = vdev; - sdi->driver = di; + sdi->driver = di; sdi->dev_type = DEV_TYPE_DEMO; devices = g_slist_append(devices, sdi); - return devices; + return devices; } static const GSList *hw_dev_mode_list(const struct sr_dev_inst *sdi) @@ -527,7 +523,6 @@ static int hw_dev_open(struct sr_dev_inst *sdi) return SR_OK; } - //扫描目录文件 scan_dsl_file(sdi); struct session_vdev* vdev = sdi->priv; @@ -546,7 +541,6 @@ static int hw_dev_open(struct sr_dev_inst *sdi) vdev->unit_bits = 8; } - //固定值 vdev->ref_min = 1; vdev->ref_max = 255; @@ -564,7 +558,6 @@ static int hw_dev_open(struct sr_dev_inst *sdi) packet_interval = g_timer_new(); run_time = g_timer_new(); - //这个可以再看下怎么改 init_random_data(vdev); ret = load_virtual_device_session(sdi); @@ -604,12 +597,10 @@ static int hw_dev_close(struct sr_dev_inst *sdi) } g_safe_free(vdev->packet_buffer); - //数据 g_safe_free(vdev->logic_buf); g_safe_free(vdev->analog_buf); g_safe_free(sdi->path); - //不释放也可以? // g_timer_destroy(packet_interval); // g_timer_destroy(run_time); @@ -624,7 +615,7 @@ static int dev_destroy(struct sr_dev_inst *sdi) { assert(sdi); hw_dev_close(sdi); - sdi->path = NULL; + sdi->path = NULL; sr_dev_inst_free(sdi); } @@ -810,17 +801,14 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, break; case SR_CONF_DEVICE_MODE: sdi->mode = g_variant_get_int16(data); - //恢复默认信号模式 switch (sdi->mode) { case LOGIC: - //默认为第一个协议模式(后面添加枚举) if("" != get_dsl_path_by_pattern_mode(sdi->mode,PATTERN_DEFAULT)) { cur_sample_generator = pre_sample_generator = PATTERN_DEFAULT; sdi->path = g_strdup(get_dsl_path_by_pattern_mode(sdi->mode,PATTERN_DEFAULT)); } - //没有第一个协议 else { cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; @@ -828,11 +816,9 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, } break; case DSO: - //默认为RANDOM cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; sdi->path = g_strdup(""); case ANALOG: - //默认为RANDOM cur_sample_generator = pre_sample_generator = PATTERN_RANDOM; sdi->path = g_strdup(""); default: @@ -843,7 +829,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, case SR_CONF_PATTERN_MODE: stropt = g_variant_get_string(data, NULL); pre_sample_generator= cur_sample_generator; - //字符串有效 if(get_pattern_mode_index_by_string(sdi->mode , stropt) != PATTERN_INVALID) { switch (sdi->mode) @@ -860,29 +845,28 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, default: break; } - //文件无效 if ("" == (sdi->path = get_dsl_path_by_pattern_mode(sdi->mode,cur_sample_generator)) && cur_sample_generator != PATTERN_RANDOM) { cur_sample_generator = pre_sample_generator; } } - //字符串无效,返回 else { cur_sample_generator = pre_sample_generator; } - //模式发生切换,需要重新载入 if(cur_sample_generator != pre_sample_generator) { - is_change = TRUE; + // is_change = TRUE; + pre_sample_generator = cur_sample_generator; + // load_virtual_device_session(sdi); } - + sr_dbg("%s: setting pattern to %d", __func__, cur_sample_generator); break; - + case SR_CONF_MAX_HEIGHT: stropt = g_variant_get_string(data, NULL); for (i = 0; i < ARRAY_SIZE(maxHeights); i++) @@ -901,7 +885,6 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, break; case SR_CONF_PROBE_VDIV: ch->vdiv = g_variant_get_uint64(data); - //重新读取 if(sdi->mode == DSO) { if(vdev->packet_buffer) @@ -977,14 +960,13 @@ static int config_set(int id, GVariant *data, struct sr_dev_inst *sdi, break; case SR_CONF_CAPTURE_NUM_PROBES: vdev->num_probes = g_variant_get_uint64(data); - break; + break; case SR_CONF_INSTANT: instant = g_variant_get_boolean(data); break; case SR_CONF_DEMO_CHANGE: is_change = g_variant_get_boolean(data); break; - //初始化DEMO case SR_CONF_DEMO_INIT: pre_sample_generator = cur_sample_generator; load_virtual_device_session(sdi); @@ -1079,9 +1061,9 @@ static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi, } static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, - void *cb_data) + void *cb_data) { - + (void)cb_data; struct session_vdev *vdev; @@ -1101,7 +1083,6 @@ static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, vdev->cur_block = 0; vdev->cur_channel = 0; - //在启动前检查文件是否有效 if(cur_sample_generator != PATTERN_RANDOM) { if (vdev->archive != NULL) @@ -1205,7 +1186,7 @@ static int hw_dev_acquisition_start(struct sr_dev_inst *sdi, } packet_time = 1/(double)22; } - + vdev->analog_buf_len = 0; vdev->analog_read_pos = 0; @@ -1324,7 +1305,7 @@ static int receive_data_logic(int fd, int revents, const struct sr_dev_inst *sdi { bToEnd = 1; } - + if(!bToEnd) { packet.type = SR_DF_LOGIC; @@ -1333,7 +1314,7 @@ static int receive_data_logic(int fd, int revents, const struct sr_dev_inst *sdi logic.index = 0; logic.order = 0; logic.length = chan_num * packet_len; - //防止越界 + post_data_len += logic.length / enabled_probe_num; if(post_data_len >= vdev->total_samples/8) { @@ -1341,7 +1322,6 @@ static int receive_data_logic(int fd, int revents, const struct sr_dev_inst *sdi last_packet_len = (vdev->total_samples/8) - last_packet_len; logic.length = last_packet_len * enabled_probe_num; } - //注意传输缓冲 uint64_t random = vdev->logic_buf_len - logic.length; random = abs(rand()) %random; logic.data = vdev->logic_buf + random; @@ -1449,10 +1429,28 @@ static int receive_data_logic_decoder(int fd, int revents, const struct sr_dev_i pack_buffer->block_buf_len = 0; pack_buffer->block_data_len = 0; pack_buffer->block_chan_read_pos = 0; + + max_probe_num = chan_num; } pack_buffer = vdev->packet_buffer; - //传输块长度需要更新 + if(chan_num != max_probe_num) + { + for(ch_index = 0 ;ch_index < chan_num; ch_index++) + { + if(pack_buffer->block_bufs[ch_index] != NULL) + { + g_free(pack_buffer->block_bufs[ch_index]); + } + pack_buffer->block_bufs[ch_index] = NULL; + pack_buffer->block_read_positions[ch_index] = 0; + } + pack_buffer->block_buf_len = 0; + pack_buffer->block_data_len = 0; + pack_buffer->block_chan_read_pos = 0; + max_probe_num = chan_num; + } + if(pack_buffer->post_buf_len != chan_num * packet_len) { pack_buffer->post_buf_len = chan_num * packet_len; @@ -1474,7 +1472,7 @@ static int receive_data_logic_decoder(int fd, int revents, const struct sr_dev_i // Make packet. read_chan_index = 0; dir_index = 0; - + while (pack_buffer->post_len < pack_buffer->post_buf_len) { if (pack_buffer->block_chan_read_pos >= pack_buffer->block_data_len) @@ -1568,7 +1566,7 @@ static int receive_data_logic_decoder(int fd, int revents, const struct sr_dev_i vdev->cur_block++; pack_buffer->block_chan_read_pos = 0; } - + p_wr = (uint8_t*)pack_buffer->post_buf + pack_buffer->post_len; p_rd = (uint8_t*)pack_buffer->block_bufs[read_chan_index] + pack_buffer->block_read_positions[read_chan_index]; *p_wr = *p_rd; @@ -1613,7 +1611,7 @@ static int receive_data_logic_decoder(int fd, int revents, const struct sr_dev_i logic.length = last_packet_len * enabled_probe_num; } logic.data = pack_buffer->post_buf; - + gdouble packet_elapsed = g_timer_elapsed(packet_interval, NULL); gdouble waittime = packet_time - packet_elapsed; if(waittime > 0){ @@ -1705,7 +1703,6 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) return SR_ERR_MALLOC; } - //初始化读取块 for (ch_index = 0; ch_index <= chan_num; ch_index++){ vdev->packet_buffer->block_bufs[ch_index] = NULL; vdev->packet_buffer->block_read_positions[ch_index] = 0; @@ -1713,7 +1710,6 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) vdev->packet_buffer->post_buf_len = chan_num * 10000; - //不需要+1 vdev->packet_buffer->post_buf = g_try_malloc0(vdev->packet_buffer->post_buf_len); if (vdev->packet_buffer->post_buf == NULL){ sr_err("%s: vdev->packet_buffer->post_buf malloc failed", __func__); @@ -1727,8 +1723,6 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) pack_buffer->block_chan_read_pos = 0; } pack_buffer = vdev->packet_buffer; - - //重新分配缓冲 if(pack_buffer->post_buf_len != chan_num * 10000) { vdev->packet_buffer->post_buf_len = chan_num * 10000; @@ -1746,29 +1740,44 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) pack_buffer->post_len = 0; } + if(chan_num != max_probe_num) + { + for(ch_index = 0 ;ch_index < chan_num; ch_index++) + { + if(pack_buffer->block_bufs[ch_index] != NULL) + { + g_free(pack_buffer->block_bufs[ch_index]); + } + pack_buffer->block_bufs[ch_index] = NULL; + pack_buffer->block_read_positions[ch_index] = 0; + } + pack_buffer->block_buf_len = 0; + pack_buffer->block_data_len = 0; + pack_buffer->block_chan_read_pos = 0; + max_probe_num = chan_num; + } + // Make packet. read_chan_index = 0; dir_index = 0; if(vdiv_change) { - //随机 if(cur_sample_generator == PATTERN_RANDOM) { - //波形不太理想 for(int i = 0 ; i < pack_buffer->post_buf_len ;i++) { *(uint8_t*)(pack_buffer->post_buf + i) = rand()%40 +110; } pack_buffer->post_len = pack_buffer->post_buf_len; } - //文件 else { + pack_buffer->post_len = 0; while (pack_buffer->post_len < pack_buffer->post_buf_len) - { + { if (pack_buffer->block_chan_read_pos >= pack_buffer->block_data_len) - { + { if (vdev->cur_block >= vdev->num_blocks){ bToEnd = 1; break; @@ -1776,15 +1785,15 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) for (ch_index = 0; ch_index < chan_num; ch_index++) { - bCheckFile = 0; + bCheckFile = 0; while (1) { - if (sdi->mode == LOGIC) + if (sdi->mode == LOGIC) snprintf(file_name, sizeof(file_name)-1, "L-%d/%d", dir_index++, vdev->cur_block); else if (sdi->mode == DSO) snprintf(file_name, sizeof(file_name)-1, "O-%d/0", dir_index++); - + if (unzLocateFile(vdev->archive, file_name, 0) == UNZ_OK){ bCheckFile = 1; break; @@ -1803,18 +1812,18 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) if (unzGetCurrentFileInfo64(vdev->archive, &fileInfo, szFilePath, sizeof(szFilePath), NULL, 0, NULL, 0) != UNZ_OK) - { + { sr_err("%s: unzGetCurrentFileInfo64 error.", __func__); send_error_packet(sdi, vdev, &packet); return FALSE; } - if (ch_index == 0){ + if (ch_index == 0){ pack_buffer->block_data_len = fileInfo.uncompressed_size; - + if (pack_buffer->block_data_len > pack_buffer->block_buf_len) { - for (malloc_chan_index = 0; malloc_chan_index < chan_num; malloc_chan_index++){ + for (malloc_chan_index = 0; malloc_chan_index < chan_num; malloc_chan_index++){ // Release the old buffer. if (pack_buffer->block_bufs[malloc_chan_index] != NULL){ g_free(pack_buffer->block_bufs[malloc_chan_index]); @@ -1827,7 +1836,7 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) send_error_packet(sdi, vdev, &packet); return FALSE; } - pack_buffer->block_buf_len = pack_buffer->block_data_len; + pack_buffer->block_buf_len = pack_buffer->block_data_len; } } } @@ -1840,7 +1849,7 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) } } - // Read the data to buffer. + // Read the data to buffer. if (unzOpenCurrentFile(vdev->archive) != UNZ_OK) { sr_err("cant't open zip inner file:\"%s\"", file_name); @@ -1859,13 +1868,13 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) pack_buffer->block_read_positions[ch_index] = 0; // Reset the read position. } vdev->cur_block++; - pack_buffer->block_chan_read_pos = 0; + pack_buffer->block_chan_read_pos = 0; } p_wr = (uint8_t*)pack_buffer->post_buf + pack_buffer->post_len; p_rd = (uint8_t*)pack_buffer->block_bufs[read_chan_index] + pack_buffer->block_read_positions[read_chan_index]; *p_wr = *p_rd; - + pack_buffer->post_len++; pack_buffer->block_read_positions[read_chan_index]++; @@ -1890,8 +1899,7 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) } } } - - //处理vdiv + for(int i = 0 ; i < pack_buffer->post_buf_len; i++) { tem = 0; @@ -1916,7 +1924,7 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) val = 128 - temp_val; tem = val * 1000 / vdiv; tem = 128 - tem; - + if(tem == 0) temp_val = 1; else @@ -1928,7 +1936,6 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) vdiv_change = FALSE; } - //计算时间 gdouble total_time = vdev->timebase /(gdouble)SR_SEC(1)*(gdouble)10; gdouble total_time_elapsed = g_timer_elapsed(run_time, NULL); if (total_time_elapsed < total_time && !instant) @@ -1941,7 +1948,6 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) } else { - //数据循环 uint8_t top0; uint8_t top1; if(cur_sample_generator == PATTERN_RANDOM) @@ -1979,7 +1985,7 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) dso.mqflags = SR_MQFLAG_AC; dso.num_samples = pack_buffer->post_len / chan_num; dso.data = pack_buffer->post_buf; - + gdouble packet_elapsed = g_timer_elapsed(packet_interval, NULL); gdouble waittime = packet_time - packet_elapsed; if(waittime > 0){ @@ -2001,17 +2007,12 @@ static int receive_data_dso(int fd, int revents, const struct sr_dev_inst *sdi) packet.type = SR_DF_END; ds_data_forward(sdi, &packet); sr_session_source_remove(-1); -// if(cur_sample_generator != PATTERN_RANDOM) -// { -// close_archive(vdev); -// } } return TRUE; } -//修改称原有版本(读取文件) static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sdi) { struct session_vdev *vdev = sdi->priv; @@ -2044,7 +2045,6 @@ static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sd sr_err("%s:cant' malloc",__func__); return SR_ERR_MALLOC; } - //随机数据 if(cur_sample_generator == PATTERN_RANDOM) { for(int i = 0 ; i < 206 ;i++) @@ -2052,7 +2052,6 @@ static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sd *(uint8_t*)(analog_data + i) = rand()%40 +110; } } - //文件 else { snprintf(file_name, sizeof(file_name)-1, "%s-%d/%d", "A", @@ -2077,10 +2076,9 @@ static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sd sr_err("read zip inner file error:\"%s\"", file_name); send_error_packet(sdi, vdev, &packet); return FALSE; - } + } } - //计算放大后数据 gdouble rate = 103 / (gdouble)2048 ; uint64_t total_buf_len = rate * vdev->total_samples; @@ -2103,7 +2101,6 @@ static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sd vdev->analog_buf_len = total_buf_len; uint64_t per_block_after_expend = total_buf_len /206; - //根据vdiv对电压进行放大 probe = g_slist_nth(sdi->channels, 0)->data; uint64_t p0_vdiv = probe->vdiv; probe = g_slist_nth(sdi->channels, 1)->data; @@ -2142,7 +2139,6 @@ static int receive_data_analog(int fd, int revents, const struct sr_dev_inst *sd temp_value = tem; } - //对数据进行拓展 for(int j = 0 ; j analog_read_pos + packet_len >= vdev->analog_buf_len - 1 ) { @@ -2263,13 +2258,11 @@ static int load_virtual_device_session(struct sr_dev_inst *sdi) int version = 1; assert(sdi); - //如果不是random要检查文件 if (cur_sample_generator != PATTERN_RANDOM) { assert(sdi->path); } - //逻辑分析仪初始化(RANDOM) if (sdi->mode == LOGIC && cur_sample_generator == PATTERN_RANDOM) { sdi->driver->config_set(SR_CONF_SAMPLERATE, @@ -2297,7 +2290,6 @@ static int load_virtual_device_session(struct sr_dev_inst *sdi) } adjust_samplerate(sdi); } - //示波器初始化 else if(sdi->mode == DSO) { sdi->driver->config_set(SR_CONF_SAMPLERATE, @@ -2330,7 +2322,6 @@ static int load_virtual_device_session(struct sr_dev_inst *sdi) } adjust_samplerate(sdi); } - //数据记录仪初始化 else if(sdi->mode == ANALOG) { sdi->driver->config_set(SR_CONF_SAMPLERATE, @@ -2353,7 +2344,6 @@ static int load_virtual_device_session(struct sr_dev_inst *sdi) return SR_ERR; } - //做一个用于通道初始化的函数 probe->enabled = TRUE; probe->bits = 8; probe->vdiv = 1000; @@ -2371,7 +2361,6 @@ static int load_virtual_device_session(struct sr_dev_inst *sdi) } adjust_samplerate(sdi); } - //协议文件初始化 else { archive = unzOpen64(sdi->path); @@ -2515,21 +2504,21 @@ static int load_virtual_device_session(struct sr_dev_inst *sdi) SR_PRIV struct sr_dev_driver demo_driver_info = { .name = "virtual-demo", - .longname = "Demo driver and pattern generator", - .api_version = 1, + .longname = "Demo driver and pattern generator", + .api_version = 1, .driver_type = DRIVER_TYPE_DEMO, - .init = hw_init, + .init = hw_init, .cleanup = NULL, - .scan = hw_scan, + .scan = hw_scan, .dev_mode_list = hw_dev_mode_list, - .config_get = config_get, - .config_set = config_set, - .config_list = config_list, - .dev_open = hw_dev_open, - .dev_close = hw_dev_close, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = hw_dev_open, + .dev_close = hw_dev_close, .dev_destroy = dev_destroy, .dev_status_get = hw_dev_status_get, - .dev_acquisition_start = hw_dev_acquisition_start, - .dev_acquisition_stop = hw_dev_acquisition_stop, - .priv = NULL, + .dev_acquisition_start = hw_dev_acquisition_start, + .dev_acquisition_stop = hw_dev_acquisition_stop, + .priv = NULL, }; diff --git a/libsigrok4DSL/hardware/demo/demo.h b/libsigrok4DSL/hardware/demo/demo.h index 6073711a..d0e253ff 100644 --- a/libsigrok4DSL/hardware/demo/demo.h +++ b/libsigrok4DSL/hardware/demo/demo.h @@ -24,12 +24,7 @@ #include #include "../../libsigrok-internal.h" #include -//原版导入方式**(channel_modes冲突) -#include"../DSL/dsl.h" - -/*修改*/ -//信号模式 enum DEMO_PATTERN { PATTERN_INVALID = -1, PATTERN_RANDOM = 0, @@ -43,35 +38,38 @@ static int pattern_logic_count = 1; static int pattern_dso_count= 1; static int pattern_analog_count= 1; -//协议采样率、总样本数列表 static uint64_t samplerates_file[1]; static uint64_t samplecounts_file[1]; -//定时器 static GTimer *packet_interval = NULL; static GTimer *run_time = NULL; -//首次开启 static gboolean is_first = TRUE; static gboolean is_change = FALSE; -//总共启用通道数(LOGIC会使用) static int enabled_probe_num; -//包长度、包时间、总传输包长度 static uint64_t packet_len; static gdouble packet_time; static uint64_t post_data_len; -//文件路径 extern char DS_RES_PATH[500]; -//示波器垂直分辨率变化 static gboolean vdiv_change; -//立即 static gboolean instant = FALSE; -//路径 +static int max_probe_num = 0; extern char DS_RES_PATH[500]; -//信号模式(起始一样) uint8_t cur_sample_generator; uint8_t pre_sample_generator; struct session_packet_buffer; +static const uint64_t vdivs10to2000[] = { + SR_mV(10), + SR_mV(20), + SR_mV(50), + SR_mV(100), + SR_mV(200), + SR_mV(500), + SR_V(1), + SR_V(2), + 0, +}; + struct session_vdev { int version; @@ -80,14 +78,13 @@ struct session_vdev uint16_t samplerates_min_index; uint16_t samplerates_max_index; - //逻辑分析仪随机数据 + void *logic_buf; uint64_t logic_buf_len; - //数据记录仪周期数据 + void *analog_buf; uint64_t analog_buf_len; uint64_t analog_read_pos; - //示波器周期数据 int cur_channel; int cur_block; @@ -110,8 +107,6 @@ struct session_vdev struct session_packet_buffer *packet_buffer; }; - - #define SESSION_MAX_CHANNEL_COUNT 512 struct session_packet_buffer @@ -127,9 +122,6 @@ struct session_packet_buffer uint64_t block_read_positions[SESSION_MAX_CHANNEL_COUNT]; }; - -/*修改*/ - struct DEMO_caps { uint64_t mode_caps; uint64_t feature_caps; diff --git a/libsigrok4DSL/lib_main.c b/libsigrok4DSL/lib_main.c index f5181438..d4693124 100644 --- a/libsigrok4DSL/lib_main.c +++ b/libsigrok4DSL/lib_main.c @@ -647,7 +647,6 @@ SR_API int ds_get_actived_device_info(struct ds_device_full_info *fill_info) strncpy(p->driver_name, dev->driver->name, sizeof(p->driver_name) - 1); } - //demo paht if ((dev->dev_type == DEV_TYPE_FILELOG || dev->dev_type == DEV_TYPE_DEMO) && dev->path != NULL){ strncpy(p->path, dev->path, sizeof(p->path) - 1); } diff --git a/libsigrok4DSL/libsigrok.h b/libsigrok4DSL/libsigrok.h index 90fa7d23..3da86f79 100644 --- a/libsigrok4DSL/libsigrok.h +++ b/libsigrok4DSL/libsigrok.h @@ -1033,7 +1033,6 @@ enum sr_config_option_id /** The device supports setting the number of data blocks. */ SR_CONF_NUM_BLOCKS = 30104, - /** demo **/ SR_CONF_LOAD_DECODER = 30105, SR_CONF_DEMO_INIT = 30106,