From a6fa12ab3b199b07b798d530a5949e9be69942b0 Mon Sep 17 00:00:00 2001 From: f4exb Date: Tue, 23 May 2023 10:23:18 +0200 Subject: [PATCH] Aaronia RTSA output: initial commit --- doc/img/AaroniaRTSAOutput.png | Bin 0 -> 21604 bytes doc/img/AaroniaRTSAOutput.xcf | Bin 0 -> 75411 bytes doc/img/aaronia_http_tx.jpg | Bin 0 -> 22984 bytes doc/img/aaronia_http_tx_iqmod.jpg | Bin 0 -> 17441 bytes .../aaroniartsaoutput/CMakeLists.txt | 2 + .../aaroniartsaoutput/aaroniartsaoutput.cpp | 121 +++++++++++- .../aaroniartsaoutput/aaroniartsaoutput.h | 33 +++- .../aaroniartsaoutputgui.cpp | 87 ++++++++- .../aaroniartsaoutput/aaroniartsaoutputgui.h | 13 +- .../aaroniartsaoutput/aaroniartsaoutputgui.ui | 166 ++++++++++++++-- .../aaroniartsaoutputplugin.cpp | 6 +- .../aaroniartsaoutputplugin.h | 10 +- .../aaroniartsaoutputsettings.cpp | 39 +++- .../aaroniartsaoutputsettings.h | 23 ++- .../aaroniartsaoutputwebapiadapter.h | 5 + .../aaroniartsaoutputworker.cpp | 183 ++++++++++++++++++ .../aaroniartsaoutputworker.h | 88 +++++++++ .../samplesink/aaroniartsaoutput/readme.md | 52 ++++- .../aaroniartsainput/aaroniartsainput.cpp | 6 +- sdrbase/resources/webapi/doc/html2/index.html | 26 ++- .../doc/swagger/include/AaroniaRTSA.yaml | 30 ++- .../doc/swagger/include/DeviceReports.yaml | 2 +- .../doc/swagger/include/GS232Controller.yaml | 8 +- .../api/swagger/include/AaroniaRTSA.yaml | 30 ++- .../api/swagger/include/DeviceReports.yaml | 2 +- swagger/sdrangel/code/html2/index.html | 26 ++- .../qt5/client/SWGAaroniaRTSAOutputReport.cpp | 49 ++--- .../qt5/client/SWGAaroniaRTSAOutputReport.h | 14 +- .../client/SWGAaroniaRTSAOutputSettings.cpp | 71 +++++++ .../qt5/client/SWGAaroniaRTSAOutputSettings.h | 18 ++ .../code/qt5/client/SWGDeviceReport.cpp | 30 +-- .../code/qt5/client/SWGDeviceReport.h | 8 +- 32 files changed, 996 insertions(+), 152 deletions(-) create mode 100644 doc/img/AaroniaRTSAOutput.png create mode 100644 doc/img/AaroniaRTSAOutput.xcf create mode 100644 doc/img/aaronia_http_tx.jpg create mode 100644 doc/img/aaronia_http_tx_iqmod.jpg create mode 100644 plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.cpp create mode 100644 plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.h diff --git a/doc/img/AaroniaRTSAOutput.png b/doc/img/AaroniaRTSAOutput.png new file mode 100644 index 0000000000000000000000000000000000000000..c5867e55f64b74afe3e6a897a93ecb2641fb8de3 GIT binary patch literal 21604 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 literal 0 HcmV?d00001 diff --git a/doc/img/AaroniaRTSAOutput.xcf b/doc/img/AaroniaRTSAOutput.xcf new file mode 100644 index 0000000000000000000000000000000000000000..d1ce91dbb0f747ed7051fb7804942181b1d050a4 GIT binary patch literal 75411 zcmeEv2Ygh;_Wx!#1w!@teE!xv5V#OR3xoh6B%8gv2_TS=N)kE=1PIbWN(8btM8*EF zKLqSpQJzY(0Kr03#Am^R3W|tQ5=h^@_y0XJb8qf$HZ;pa|0bV1XXebzy>sWzoO9+o zWv3L*nB8vC#L4Xz^ooiynM?s6;kpDK`nw0$MYsY2;9QKWNg`Nu;qULb0&!7-e+WON zqs%99wU~li_n0_q#*BiQ^AR>tI z%q^TmJWBmc#Ju^7rx&!FH*0#~q%NTmlc!9aHGS6Hb`gy9m^&puuU#+pAJqlX`F^6K z+OdC%UNmoZ-o(P0Q`$xKLTIs9NCbLZHM4MjyTX|hrxwhk9J3}*o>wrx9ZPTUbFX(| zDzo7);0O-{2XWf67pH%Fm{aR|PTQ1o+UY2#U1d(Ar*PVT3#UoE(oI)<%EPITbDH@) zr=wRh8qhYMhlLv;-D(J53O{`+s#{CD7>Y5IgTG*0^fgsn?a6O;P}nZe)O;BR5@w}Kzf3wQ+dC0rpQj_%({_(4n^$*@)AJS=%ms_R*U<>#wd>F>rdE&zm{rDzxc#9SUalxN08V zDL-#sL61p=a|e3F zt`ahl-@#uZ8&;R{%!K1jT#CePz* z)`T#hnb9UDx4LG{dSW#(dDg9gOFm>+O>T(Evv$qerrd|ykrJ@LGD8feC6k$AF)o2rwg@v1dj}qYGGz1h+M;xcdXQC9UZz7A)entJimo_ehcyZ7UKCWeir%NoSIC<_&UGq75Ij!*m(UJ zpWj?HscRC>=`yV;rd%p=ox^2P&odX*dh<6-ZPv7Bm%8RM2=n$R@vlqSGgLeSm#X64 zzXAPSo?&dU)y#r_RyCM zl7HVT;C557;es6g5!cN^9@C(0pzsd>?I8S`CCEn+{fK)3nFs*|D9`=4&Uf@cqmc6& zJ@mUkMh{UKJ@oJ8{nrO$Sd0yR?a@Q)D^OY5pVlsf{nUDr76Gco!P|O?#`iXjLrlTU zAP+W$c+nsj-l34zK`^k%SPw!x*}|G3A7pB(28wtK(lqq*cVEzG_gEmv zhvI5>zrE|d($ZZh91B}O)!km9_j#!DgVNI7JNF{-2gJamaU;474E)^zr2)I?_QsN8 zkWtFUVP0l^h^gkHo4=^qcWq1L#rrCke~lsYA|9yTp_axsxvZ#=f_RGr^-ybG#hw-F z5?;yG&#Up*{a95xp4YW!tNJ)@P|R~wzNG$?+VXFC)ir-ZA#n@Oz3P06$+JpL65;V8 zoXEqKt;>E+ZE;avbyaI(;H~n5RCONREyPrtx~rmMR~9|U_oFmAGP%&ij@G8nTkN#d z@4!44ud5I1qYTlrF8+kaS(giXm!KR2VgWr5LYIhf{3Wc?5FW(SUy?28WI-1QD(-v9 zJtF+Lpf3x$OVCdQJtSx)r~e2R^dEwT3))Z6L4sxrI$6*KoL>64pf3x$OVCdQJtSx) zr~el$=syG%@&6~{ts>qk;;rF4owc8!g9ObMbh4leIE8)s8`xNFyDv#65^bawE&$w~SNK||O+I9D@d)Ulo003zNwx@{ZERtpbG!D2A*Zh0^>a}au z5d4i)A#2q8xes>c8f7iJJ*+_ks^1XN*9HO_)dmO})%gCAe-sOrD`D?^CZK*mp{3{f zeQi?jVGF9OHB8yV+)Ot5J+0L{xGi1pt8T4+^JCS=%bL_DSKe+)r3f-rwOVg)^^Xx> zs|$FkJl)luuYr(&#XQaq$=-(@<8?97nhb-d{D%m;#>Si zP3j9yo@lN0eC0`V?FO8-t*8&{=CSB9mv`ZDo!$}jV?n?5lLxGJi#fmDO@b2QfWLN6 z3A#y8aldx^MEFNRYdCG+R8Xs+T?CC4bcmoM1uYbGF{d3we1|zAd_Sj>NGFMO(oKS| z#XrTv9is#tDd;tvc4{i9RnRVi#tJ$_P?4`wp$IP)^d>>?7xXDXH*xxxNzF~izNXMM zeb^PS#s+D3u2&P7pSXvLd*BLCk^h{pU+ErXa-zo-n_O#(EiTQkHt?Tgx}Y_&rl51K z7p)#+Svi7K+~b_Er}sU}bU?#S`(D%n=qhfp*@U#G{gU*h={nc64TcD3`d+@@=Z`pq=tI)@LK{M? zM48T4<xzaw}bA(p058_h zVhUto4Q!{?DJtx2N)rsK`3cky5PY&-&B7lDeMUgBMtxW3XklOD)*Hlc3f$hz@OYGq zQIv~OfX;hM-vfG&0ui$Qp4%h>!KRwsrSEH@AXD|*rMpe_!GKb;$s>{mnwkRQM=?tS zP3i|tgdgjhM7%#A3T!~{{UP^FP3}v6Qt#lk>3-^a?rmbKOFKD&`%(Cdekkap2iCo8 z5&;x`$kEHR5DMS&;7F(qo-)X!Jn%G1FM=quwTY_E=GCmW)BGs4Na4@tTj7n4CN4P9 zqBY#}6)nbva=2HwMD2!#DiFP=+d>`}Ez(4%ituPZdBE!a7Uy^WRL~y;t>Ux?l^K6M zs3#KbENG0Ng9XhIbc&!01-((wdj)+$&{qU~i_@Nu3Hm*!y*hE)+af5f0mff%T6IY@ zT2S$xy)#94qM-8xy-v`(1${)&mjvA*=tqJc6!avg(H2237E}^6np0RBXVTWccD%3l z|F!Rbru+FmKcF9`LHn}n^!AZv)&BOBm!~+$g+&G^T`5Y3E1(olz5p&>9#%T4>kGX8 zP(qVSEpCFkB+BZP@k#}+wEj&RP5X=TOKO-&I<4jX+qbCtmQ7`$t2pQ(d^;=yFGc7A zXjQyrQ(5R@rDLrNCA@I!?@Y4BH{MtF_{RU%Vc+Km$$z|MQ%rMRKqIdJG8M=?3Bg5X z%s+9F`WGh688=-tMOxpHR}b(S*>n+bk+$g~`T`kw^@@y+>fJB4Z~cyo7%ZfU=^fiA zDyp8>7rdxG{bTy{uII)67E7!8K7z{A{w{^*AGpNF==-`B0jkBp+xJtAe`y*Fb^U_n z?@G0#DXEzlRit6YB0V@wO~H5z{;G_$^yCStX=&*c#uQCv8n^*zO-;(=Of&O_m;%#~ z1xyU*($pa$dPFLZ#ykp3hP*DGH^@|%o|Zajh=uVnxs#?2=TB2cqz9$Zos7l93Z}G6 zH-n>Jm~V1z-elgaY}$&%n^EE|L7SB=ui_>MRBhS3Y1`{tw`_(#U^5=Ob@L|jVYpXn z-i)O1qs*JtO_UjB-mJdNr*k;Vk5BQ>2s3UI5RP(tQR3A^M0O1C9NvjPs{WyPc(@utw=*C&TH>H4I4AB9ob9n{CjhoT2{ zTBl}{AH^MGR+X>vDL)T*D((&u$(r_9r`}C|Ok{oaGkI_q^TBHJ;r=TY_h{C#-!tm# zJglz4!^@(0p!$+U@0L~XTh)$kjJGgcmtw|SpT&U%VA!>Cp~+UQQ=YeMHSAKMd&Rz{ z-?6?5glLEryET&L@-#`y1l3mcBB)mz{BcemAD1C$zMvw1+_fTnm!RteeNoWug6`!s z;d4&yT?H)?^j%J!BAxSq2$yr3XcqKuf_4zJx1dfzGX%{SbgrP+3VN5I>jZsK(Cvcm z74(3h<(wv&1^t_#9R%$ys8i4kLGw936_5s_{10;R zG8dchcJv0D@dmg8HscNcAQvyQ{s!TA16%>&c!NL4Mdb|+*WW-z2v_~E>-QYuo!_&l zyum7e0~ZaJ(~3jUqKLAV#dwb)7EKS+P)a*4`Im;MGY(t7_v`a73PR9?FDH&79}V4$9}kpom-y4V|>tG@J2 z|7(ZOq_2PN=lR~x_xXQBxP)0@7Z6;+ppL090nZmMp?tn@2|*~0z$GUAjEdeD3S9F0 zol!C9InCAv)!+^>-Wepu6)c4ohrpl%S{{FET>~DrV2$Z|j4HA8l$N`y>oDMiziRE8 zhadj;TCpq@<5YMlh8Dr9Y^iFf$-N#2QxFp~weUVncWGi$*YkrbLQL+}53gB=qZhE6 z){J$sbTkF_SUtRE%{uI{(w_G)e;#`_^J8>-R%>0gwW*wHYgaWIig|e4*)R{!Ppt?6 zA4O7wLFojD`b~A-_wyZNH$VznPkrrh`G-Z#X+VyuyAOl)kDAdFQFk}qBmZBEhNI)6SRY%y#;j&njvVupmPPiR?xcyT_@;^f^HXdub>A6E$1}V zEa=|^?I37xL7jqT2%0bGTux0F1~w4-pI@}dR4geBkWIyOr(dwtR4h3Bb?-#hPN>WD z_chq*b=pOQup|A(Q$D(i1FqzEV*Aq0#_IGAGhOIere!pnSLpb3gZ|fTWh6{5 zXQ|gZKxP;QVaYU^T^c33i^AtiwbK?f>T95RFVw`e*?YUqrFbBYI#6E^6u#Q^ zrMt0~lGrH6FQO<1J4HdGD9;(zVFsJ(x?EkVe#dJ?4Ya75zt-}}4Sl|35ty3$RXjKl zVJCKxQ4wLI*ZX~|&0wH;+qD;*K+u}o`3eNlp0(R#y{P#NRUp!29pZ7Liv(RR=v{vD zfR){k^RovDnl0#LK^F)r?vs6w2tO|9%bey$a5_@h&m-51@Mb~9*mR`mlOvA^el4e? zLIu4{(5`|G5Ok=ZqXeBMXpx{d3;KYd>jm8`=(~b`F6a?KYdIYqD(Gc`b`^AhphE>6 zCFnFxVR4;F$N$>#zBYs9_g(I&EoFq|L{I)5mojS06!B!L)BoXni$U6%LJbLe7EW;Omld+*=65B=KrKhynu`|z34|Jw1s&;LW%{Q^G>G&H0skIjvpAXh0}GtUKT$o-W|xNt}Q2i=6(07FDvp&a%?KPm4&UPyb+9jj-+a z$PxSFC34$KN@R44$lB;0k`x&o7)iW#k~=bC;`C-Ss;5s(h$OFNh8uk8@={N9{^Y=1 z_q5w@pB9)~J2^j^hk2wDIV~v1eVeM@1~M&@g?LPLEuftKL_bolVh} z?AjSyDM3i7`-GyXW<}j&F751cr~ z(iM&vajRLi>@uszZyhnBFftO1hssoyZX8-#QS({pM`~&5$E9URT^%_!D{G~yzGTVz z`6X3dnUys)l2{Mw>FbdG{Vy%03MH?JoH7}ycLilu?Lz9wQz9d$m@{i;84422Q+gsN z--2ysB|#Z#iCL|?WpZTXWJ^Zvw9UK}D6yWf;AWOEoh7`vATqKbD82s0M6#O5f{8cN z{nDyRRQ2YGELoaJ=2gb($bz&qB;8<1JGlW#)6ytyTAJIeisUCn6`WF3McE&Ms-2XY zdK0Q_r&+DMDK&LcBr&w~mm_}S@Zq1L>OUPmd}3te#Gv8qMwg@Z@>5dsK3%Z_UvWkC zr+FzU`H_+NK`A0yiOdU1cHgL~H-h9vvd}=@YNE171rBqMU%q^N;IP_J*-0Ps|T-M?ulhPtglBbjBtDuf~g9}A3mbd7xZ5xK2_%()atpxci`VDO#fE@?7%)YK4%#F zod1;0;^Q}L8o_eeur0@bx=xmpUOM&DayjpCIJ*z{&u>kdaxzC=T{3vWzQOhUs)N&H zdF#LAL*p%SZQfxy@%;yRQG(@T6!pUML+b84_|;O}N`CH@4ziD2ErRqcVsf>}k6bNk zM6MP|mzx@us}$*9u2RftHIpw)nMcas6Es{b_$~WMh%T-ES@lCv`BkX{l0k0zU>E$Y=uS5D~X%>@0$xkO&ML_`3P|DNDRo{e-$W`xT zjmp&qWjwuHrQ|0?6}(gJsjVIvf~sv?uF}WyD_8kfY*eoD&+kvJQjDiDxr(ONP_9y& z^p&ecOroC2MMumYd(miR>IL9UvZ zTs8TTtENWes)>3?WA-XV`j@K|b6UA-Iv2TWItRH*Y0pKjQu?!&tD+!hmaD!A8BoSa9WdheJ;^_<)@+pOaT1$*9~Bv6FFoVrnuZ@)gbX?6{z&(8kPtd@H! zD?O@u;vS9;1ZBJL-L&l<5K0l4UHABjy~ma{%|6UCRH*8)+n3*P%VFf0%b*9OeDC_@ z@6~5`bMGSeEx~HJTR;dCJ?`3*GtDC^M?b5oAB-bd!7`$H)ZMR*8ui-0##lzUi4!=Y z?wVt2>6MgEKnbI7xp~En(=AyCM;%bhiV0mPy!PQ&b{|@lm9^;5ds`n}Ifr#IUCPAw}_|3krrdv3}M$*9h}ZSO(>JmfrHu6}d9C0*HEXi2XoL}0C2eSJv! z$)#oLOB76>_|e*op!BMYwIAlE6T^~TyR3ZWs2ztaX&(1y)6Hot*X@dOcSzdFo9fhm zaadvA2P=U|tSp_)aRy6T?F#qEw7YAA)RSfRbKdOl)f3~8DEEMRY%%3BrztnS8kDAN zxY?XmPK+_GYg`|@x8HrJE=VmeyN^Qvy1e47C_OJoUB3!>2#; z#H``-O42!!QL}cfJ7~BiMR~QrlCp=uiA!t4^D7)BO+JJS*Kitb(H;!^S@}Gu1MzVtC>G^u4*^0R#1BjK?I?j_7meq>6A#scq7+*8BOspA42_<4lYW=HkNu#pajKZe;s_a0?-R(z+XJCCWGoHwgao1G^{ zg^hALy;v0n7UdajPOSJ@O-V$a#2eI?%!wyPhmB55^kP*QSjOjUd25yP7Vqcitor9{ zc}simkJa&b?+4TewfFYNp!cR)-KZ`Lw0kzI3$;r1$KZ8}uj*Nb23c4W zHT&Vzu{4w+BQUmR%xlMM53WlJWR2X?Anc}iN}JX?#*-G7){40yF~suIi&9$mVSSCc zA$=&7pYAuTb(CjV*sxa24T+*uKK&LZL-yDfH1_vnG8Fw~GW=yS{ADu0jQA6n43RJy z2Ih|)Hf(HuB20$Jut=B;zKlA?AUP2g*s0c@Gk$zlEG&kouqcaf&`q(FvM=m~zF~b~ zFTmyYLJaJMn6Mbw3vju;FaY+#fUp6u7vOSxAp!P6LRbRq1-RT^kYO*tJb}Fcm)i?Y z*bB}uC+r2d++Ik8y^t7|2zvo8w-=INFObo~Ty8H6guO5@Y#{6fxZGYC2zz1lLz}n% z=hh*x7r=(S;1hOJm|klT?1ia2cC5brsgnN;gS`Oz2lhe(P95V=hQY8G5;wm&7WTq5 zCHKN!7#ub@A;HM0&^g>*xB{AOcFCQv7aT9|7z)*PMc5T~yI&61Z9`x$++8vadh@Q5 zY0#T6z+~AUgY@Q5*bD1RM!;TJT5>Jyg`r_X9S(mCZZ8ajz3^g5vU5|(D(C!?TVO9h zb2yz|tO^5*UO5@|!mA}i6OkuzPRSjx7m~x06BE5y6$TdN(Vlb9>Lt#ryq}}9>YsDZ zYRW_J{bWft-n+P@SbJ}O40>;>)jLbBguSq;WU^MN{usPY@l`$3N>;&MaBg`$3HAa$ zw9V$1!|jEEuovtbcjm!fxVhvO*b8V!@$p7Zg@HrGPlCNL_KlsZ?|8Q4=|tEIXsECk z8gS|uhcYC>UdXt2^P3y4bHH9eBZs}<6LwRW(mG%-IKmvT7vOSx!A~zrfW1I{jk(-j z@YDU`VK2mo#lv2J%k2f9etTMo!St8C@Rz;t|DCn8}>q* zur{z4d>M6&L1L&K?1iW}yL~_;?1gq=?O-o>2i+8;lpSF&bPVeVdjT%D7s6pLgolO0 zUVzK(g)Xocx`cIsy#SZn3q4>j^a$$#djT%D7ka{8=o!`%_5xgPFGRs!fV~2H0WP-} zdc$7m9o8H60$gq{M8jT)4vU7p0GHbfePA#23F`xU0WP-}`oLZoHoa)sqDhIc7r=(S z;1hOJm|m+d?1hZt;^_r*U5k=nFTfarz0iPD$2gRsAM6E3(XtfS3*%jduowD;^-D-F zaw>EVw-;id*>YTyVK2ywiw8or!Md{B{c^Z&>kqv-)s+RkImML)z1cskzbyM>klu`i zy)e%;4EDlU*96!Lv0Kz)t5++Oh0{kp+k=oZ!u_5xgPFZlFZm9I+- z(dQyK%;4_dCo+LF;Y;DG7Z7%?1@*8rbz(u-tqZN z@|q>j?tLAtl9K#gi1gh%?wXpDI|oUXSPA2HkGTK4xdib`(x4ribCD*zZ-`X$&H_p5 zw(1kJbjoZL6Y8CV3uC9d%`7&@^Am_)b8z1PKlH{eH+#F`>s-StwVZzy|nTD?$RUA zcI^38f%Mb8QlHwM$iMm-DWN(Z`6a3Qzuz-UJ1Bp~y$5G!WK52f#=jy->t~{9k~HHj zY2)pZbTC7b?piDTlqN~X5|KYVLXy7BmENf;FIQfPGfO)ufBMRg3)2DWOD|TImsh?a zb-eY%J^SC0HZGH-N?DSw+bI1sNWz8uL$~eSQ#pz~|NW&F{`j;p^RfuZ?|HPVBz5{R zX3FPL(i~)8DoF>@CF$-p_1QlulBBPB_S~O)nx%4j{PRUOE>1`OqE{@^=j(4+`li(D z&5v02ho6?Bz8PPi{ih6R`pE)Td&=wgiR{OYx{noOQDW&_WH0z6`u+X8vW~2#r}uo} zt1oY&f{Vg0`QekB?mjA0RYYsspm8kChCH!`XY&Usyw7gaOGGONI+jki6DxNm}N|$Q{v>oGQyA}kG ztn1&ty#|%H5`cMiIC@a=;>k`ZIt)%bb(+}3=|MJ%sFh{GCIV7m~-5`Wxo&uWX^%}mi0Vu74bR*#J~Csf>^o{$p~>>MHY03mM$r52VGWUt$K zY?AtQpg_%6oq8zHUU^K-w%cWyq2nH)eVBVm<5~26-niF17+FaV92-! z$apIUxfVxF&Z$=%*+|L4Ar5!SYwBZWN1edLJpjO4ImtCUs}oCqOm^lVEn@^aYx3Uu zxaOz(6V1*#0f&2leYZ*^*PK{=r!p@wF&D`hBQQ~&WmY}!-I`=htP@B$zk4+U*~e5p zV|L;Y3vu^gXI<*TJ?aj#GeCgg{Poxrfa9ZY2SI}wUoi1QwMdrjb_Rj-TC1bkh3uxP zdH_m`%`{wjeJbkg0rfGv-NwOhn&oI^t0M?}XwZ{&8`QEV@6{mjH`JB*jxVVXL7_3= zncsf?dgR+Oz@3PhP2Tk2rXk0GGR)l! z7!bEvb$__^V-+<%z+=F^-E-B7LA?FKO+^OQmd&x%16=Q&bf0*8fh9JC;op`R&tvMk zCI&>jWeo2imVTanHA9*hIt#i9L&ME|JWkKkO%3>X%RYWPngJW<2zkpWf1UKSDhv?$ zUn=Y`754k7Fde;ZB{1Bo;m5{U(tJE~+; z1~l00k}Y;t?i~$Xnv--(5Us*;POaQbVps~9iXsBzdJP8uqls~JjgT{gJt>aF;Lp^_zOwUV8$18K2|c7G#CSAd9Bq^J*74+ zQ8#EX?YLP(QD@6amP3PaIF_wDu+N?vn9cd_{g&k$r_e$rr9uG_X_^Xf@Vg8`9+2D_o;I%qH* zqh%Tl9RwO|{hLY9V0vd^8VubD8Z2SQP0(OEV#_pG!;WS^YdL1iG+2X9dRh$z(DpA4 z_Lm0x{WO@4CqjcURI#d`EaR6FWVtsq7&z_Q_m*wJ(RC5++iPedG#JAaYkI~e$O-); zp}`RD)G4Nk?CHfcn2soNT#;!o9a7}LBGX_xrpS>+ronVjkwc42gXyRu#}=6e(_uvp zE;0?Ky1N%R0Wga(5P4VHBETqG9gVzR5~3TUuw*VUxK zIEu(-YVG7ggH10=c3lMx#*oD^OU6SQ7r6$L24e`K2M8j@U~r+qa$Q-2k(dRc!JJEq zout7SdguXq2n_}o8f?gtsg5gjrLOE8K>H-Zo9G*Q8bvDkG z4-LivLN+;Wt0S1u8I)gF;JP}0j0PJ{bLHYYP6kM6^DuCbS^_lKY*&#T8jLrKL~0gQ z@W;nzxrzougQYBU4ULblM+c$7Y{jmz&|M78_BfGaKpFhdU{hShv!~8+xh6n^8Sp`O zifc&%G#Ep~Jq~1Ge$rqWGnW(>O;2SS3>YCa*m&1CXfPc$WEu<|1R8AaG8;6Q-dUIi zLwAA(i!Gi24W?s=OoKJ-Xa@X{qlip{HRz%Xl1d42yTlDeQJV8D4Tq?2D<(@C0E*_UI3W~qAhx8r*bdil%FA(HwN z(hMzWE_uQ|fZ0wC1k^|1pd`iCC7Y!KoxWHqRmK5di+e@=+u(!P~&b^E^Z zo#v8z^T%^zEmD<01ZR8|D1CS57Lg?ipxN<%OVQ;vo<*8k(n31k<(hYDJ_GnCK)|AR zkfmt1F$+Mzw`S{ET1(|!XIErvpkLnCNPowx#`I1}+OkYf-&|7SCR?PFuemg!uTN#F zSvuHp-y-RxP3r89W97<}q}{Vp4ocFPZ&9x1Ql<0cjPQ=R$A=4ePrCi!=&rFFJ_(n; z8Yj*4#C2C9rQ?rE_R0aVm66gT-%67{?ATnY8ngSv@eij-1nTW8_(bY>-B+l5)bxz6 zcC7p%UV5W!#PORyIdrWgJ-F}n>kmkMzxydXQc{lFZMsuz+9y!Ds`m9joZ8>aR=2il zU(1+wOK$CA*O=VgOwKpAuj!AL3o(8Vn`of6`NXBHw)8Q zcdJM2=7chqc9@-EQVhrQ0LQ~D3mB~gRJB6giV2r;Vpp*MQT z2ae2ujyZ&+awXWZT;Kq-C!jnF!}U1Y*TmtTsvdHh9hGcp>|7^+w|W%M!caX9_Jugz zDPOBMTAY;(n{y=s(W?jWEDX@&IA3t0JL3~|V_;$>TlTt=?x|sS#ybW%>qZ|`pGyoB zx4c5U4&ip%>u~7OedTfGzF_u-X1R)25(DnA7WOf%lBlXM%{QmIYC#CAH?zHpzM0Kt zMD4)PKAC%3)yb(%#MfFwZ6Q9M19ol#?92?$)4@Fs=nXsSnbtJ^2uph>H8>+;$CtJ0 z;9fP0enR~@_<6O^JfM;VZPa`Xs2zv#EU^OLt3_;V>~{PV?9FBY@VR63rL7I2J#&nq z2Q|d^(2x31&uawaGxuq{V@6>B%OO6aYmREPkDo^06#b=dxa#=x=$m@fOzj1|f*|w_ zWA?KQt{s~{Wboib&L@4NL1$_LlnV_B1e!LuNj`qKim}X{++BPiH4dzizVX4;IJ!pq z#%J8lAvV%CJ_CP_vyr~hkpm91ahLRs57x#JH_|sgfE)A;IHYfUP&bafk-hjdg$q_m5XO--Hbk#E@JEub5 z5Yl6_C$OcG9B^|J;0Area5=uJa_H;ZCqUm6mAp*)hNT^BuSeZHK;0lp!GOMD?71cP zK;LX7b|qt^%TVvoH-x)EK$ET)>nRh{Q=o4)BB@*nwk(fw0EiR78}yBi%|YLcDcMN+ z1}ukTq7zc49&>|sAgRM#=$oO>m&}E}VMyAHMBs1ra2xcEj>5C{iEXQ5aH;wf1)94%gBJE$}8yZ6W zdGt*^#-&C;uOJA0!HE_G150a@EG(BIHYfUFfxvm zk-h=W!67oEOZo;8&@2KMgJz+G+M>MF8CMrCE*!?Wq;H^op;vThjIYOo@Z$Vz!bIk~ ziZh^Z2$!)XB(SA+93FEMJO+KkP&B?OFKOwrROp-0uEnHpSlUE;Jx1mMMg~zznq5F= zxvoO!o2!Xk$%~CZ@d(hXviKMXqtsH+U7&H|*sZD2BCo`C27W zRYBjREnS)ceS-k$8}=oPh!_~!Cv&GPU6Kra!_thWwxEGwZUV!gZ@|)lGY*zHii(q= zZ&=z<)ZmP07++SW183DNI?uH@c%nKC`i7^b=4(L2I79}0!?Ckk#Ky)>1I&;OeZ$*z zj1H1Dgw06b=)I;Pc1HR}hszoQXryl%>zGmcB0Ojs-B0?akv`tU8&4C+nx{{H*}i`^ zof+6XvZr=TU{8sTSpo2pxA?m27GuMIPb8RT$*H{U-5<-#e|-1$oSdH03EH_oWn0yM zAG-efhyGi&ZHi!Rt6p6&uDEzy!RqR5#3~$dTh;0jvk#v-b$IrO)m6lrI`*B9CgyJY z{`T7sZOfhb5wWIRb@+kIG54>?%-Zznq|66;N_CNwi_5PG%&49J&8yiN*ASy%S@|`V z^qQ+q?95J2=bU+m@5A=?O@K+Ov$8xz>}0L1k_XbNt_)P1{grz>f5VXq@tV(dQQEW!$lCVh7Hxq2xL~& zFGBrnlvc7?+y|k4wnQsAEN**f!|l&XZd$Ocl;v7vWzPy6zmZqfRIXNE8Fk-tk1low zHrxTNjBJ?RqaLZV;MaslTl{T+Rz@L5by=>w_H8FUqAIUS-gNlzPb!33rF!zN5y><6 zss{%9-3YCW=6Q?18Y+w8p`cG}f|EYP;&cx=q`Hi|uJzr};-Oc6mo3YCD$K`}vMPws z1qX(N%ATjx$FW|S!CZ#@(5xb=%Z`431#;YN&ZwDHCCiyVP70KR?Vfc68}S8T8|$}8 zqgv_B=Dqp?vf#~X@n(+q?+B8WPo`qZ;eGXbZ5^0#YcxJ0tB>R(^H{Dr}P{C+6J%2g+C6Zhf%hQ6Xu_Qzsgnbs3&)B`dY1;#UUl{ozkrRRVUo_ zX=Ux94I?xFseZFGZ>(bdR{&aycl#ELym-s^>IPzQmokj<7<Q6GflE@-}YnRIXrg4?yxUoWZb>6LP(wCErb0)g&syu(Oj@L}QZgdIB(by&Cp+qFNh~d{2&s2)i{cl{5vVjRiUvG*Ld)}023W(iqN*@H&CBZHg3;t;o1*1>j zhUhcwX=CzPam|D1V}oMj?lq+!ZmhUwL-eshpmCoX6XlBQN{Bu-uMR2kBy>@o7T`Y8kc-CTvuN?Wxi`^3Lj>B?_Oig zuR3nzoF&T^Vq+z1p~eksyse7$CQ2`At6uF}tSaFx->Vyl!LQPd@`(MTthb;=i4*eK zP`6oRLQ`eeB+FSWS_$43aS+eV{{NnlSeDjDJel|W1%l~2D)T#Sa z_2(kC6K=o!&RBK~ehF5`WSyAy`SaO3re}+j@u%!Fs{yz$Nu5=OEphwh!&lLPbeSa| zjyGqX%%1kd?cth_{@xq`IbEaO6?o@ z{DeBC;4}Qf)uO8#Ep(y2tQ;3Bl>?R?l^4TOy`nTB9hUd>C ze%j7GV=-jUoch?UW0jxg@FVQf)X(s%R-akY%2>*`M`7VgP5dDI9ec*4nN!OO_C1?kkft4ukJIwq3sUou{unzjAIbTN za>I9g|Ab|Y`#jxqx@*zdbyq#vS#;MT`CPhd z(YbWjqOu+;f8DjHvF=*bSa(H( z_1|5KsJs3-9FJ7wr@NZaT}_R3SJUabtEsW>YVy}zO=s6#^<-z!T}|iIT}|iGT}@}- zT}@}*U6Jx^yDOf5mfh9lr@PK;RJ)qat-G4ep}U&Srn{Q_byrhk-PP1scSVEs-(5}A zUH=@8M>5Im2X}CU^b4;I9QWgYMtD{`3M;bn4&U;A68|BVVEK6Rmcwsvd~&EdT$XoV zlUIFeTSpvcjUQZ+%S*18%SMB{EU!HKTbGvM=%Y_0%|A9&UjJ(1zx8pDg z%w2~{OhzQ2g(!@6FLG!br%nj}#9)REtI*zu{wWHvpCuq z7s}k=xO%=hzIOa$uf6gw>=IxJ;>(dNKA!P-p({*-aa_svRr%9id88E&G=65sG*p&fT#50mKeRS#i@$wCz2@JFo)yKrH+9~jt#dv9KcFL9p!KZkFo{H z6@#v;oKEkRRz3lHU#K=-Scx&X{KgVd8?{s$#0wC=JT;=oB3He2C##Ir?*`&IsQHyI zCD?2ecV*jbsB_f+jB7FjZQoG+^B7(uqbpoa$IP+@Z`?Ef%9kHB zv(FCq+y#CF))9Qgx<_34y@6)%L=!n!EgClf) zRG{R!VqzC;{a{_0?RA!Fz@h56M6NV-Z`-zgWXiaS9W8A=-NU+vwk?M%SUint>d1e7 z?Ux9kI2lD^KYHR{vQm_P$%@|_@+Vm-Lt~Pa#Wf;X&*j%%=!Jh-dLdbhP}LRKOe)2@ z()$fB#v=|`IU zNmd*JUUN^5`kwRK4Nlt50Lec`^ zRvb}YeUD@CK*zT)IB44jBr9#s;5^FKP_m*nzIhgs)ls!d)J84U2Jx!IYc-UtsQG8V zv)gR*)Co4exy5tM>M@Y4RR27N*N8vKniUr}qH4>`;vcs|rsAu@J$!N?BrE(PhQFa- z$(jMlTClhF_;XH3R<`9KO?@1am3dhNWu|tY2FZ&34>2*zJgJbZ@G{BDBZot>4i6jN zx9_uCAX(vKl9k7$K(dlHV=j}doZnbyxB`+D(~Xd$|f5aj~BYagf*I1ESs8|xd7*MFl*dK*0|tNBL9*V$0HUj zz?R)qSBjmMB0{p#TomVtY3xoqqZ z*DU9P$xd2G3CRjq@c7gGNY=Q-B-fasuGxw63lnLfCL}9d!4qZlBU!Nmbm>?}VxnWg zWCtx6g=D2=p`1tA8cJ5w##NKZW?c#kp4CPz)dum%W~J9^C|ObSlNP{cO>+&g(GpG4 zY~!wgWTpD&F}z0nN!C7baY;+3rerRf2APVl3U|@fc1TwEMGSvKzmgSeFKdU)URE^G z2Fc16TRL15AX%B0MNnpvti2#vvGOt|CcRjOWQCVWRvsA%$%@@Pef#E3fn8GP#hf;P5x9G+oxVZM$%sz1kj<^|G+bAX(uG7EdE2>n{^PaWb6=Ik+`5 zvsy7XqzADEweCi$q7`#Px)ICI55vf<#gWeaZaj#%vK7Q{C026+dRh{cp9 zHmFTq_*9oGBB%`wp96hD9>lejRa4Kj;y@G5?Nc#K|CR>m1136pM5T}IEJ+k{<|p>< zpF6q}3x!G*#M6iMZVFii;#0v-uRSAvlvWNvJ_&V@1}soFsA1t zd(CyDustk>p*GNYtl4Cfb%qzfbzuy2%xj+ZR2;{ zIez|Y_n2+RDP&vwpTY@G(0G*$ah^g44j5!0kO2GYr_J^wb9SY%k+3~~*CxYVQ z@pttoftFrC0rCsCndORMyXG)pK)&U<5SeyY84!Y_8fqX57{K}HTFkF!@4AM80?u{! zEq!Ur+L1Wbfk6bj>mdRyy#N9d7nCf#BImIkH!xTrasB3p@(P~VHe7%NyX!#$kv>Tv z0S@Piox8Tq+i^9+1srQ%NrY#|Vu2F;P>&L5=>;5MwwF88o$0$K@hZ7Dze02sR)B^i|{XcDZtv>|AV) zJ5Hg54Np(Zdt#F_E)F3`UWOL1bUKc}S`82Z+FunLJ7?qe7q7C!R&aRW{@34Fo$Lh` z@CXe>;0=-i1fjz9!3{!V+yo?87*G%@TyOXw6z~Dy1d9PV;P`>&x?y=npQ+0ka0HGf zXs#RjH_~E&6F8`#xo&9n?i#$uK|Z6)r2!W#QlG5xW0E_Yr8*KUSwRzPaUKM`u!`YA zjxz*;OP#hAgfDc-AJ(hy$P9DaItoQtx>fhj>)N(010X8v0SHT5HwElz#pXAdFzydw zjB-I3!{x#_2ErJc8p0SZ7sh^mbt4MG7-iw7y@fDg90_3@J~lrB!WeoF!q^y4!pD*@ z?h0WnrRV2&f-vqH))m6oE961QOBiEh|1FK_lZsP&$4p+>1qZVtl(sBA);VWBL^B&I zR1i-`0_Y=>FlNL2!E={gJsIFC3w24IyQFAB6ofGwe^jy*0vjNKNWz$;j~~|!J_%zT z4d9r7=DNWrVXT7!92(GEH~1usb!>nm1e)sxpMNDm2*Q|nI@Z8Y1_2(}cYOw7yj;aFnug7D)B?Lbd+l&Bl>V+BSkTf7^g#aR1qkCb zbveTlg1u16KL^a49b zT&dhPbo`#$wG2r}{N&hjh{jo|A<3UQ5T_h9b7o70S;b|U*aCzxbG;D<2xCGZAdGdefkO_O>js~M@oBr90eav7gyy;dMvyRuHsT0`x9bL< zgfSBY4P7n`Bqms-xM@WT#&v}-Cc#n|;^xNGw8+$B>Xiz#HAxhQk^92yiO1X)Zx9i3pfgn%3DGv+}S=gj0pTUwVbXlaVt5QN#8C~JkOkJ@oIMk=IN3FUArH=3 z)5a|6vquTp^H%-StR>NS`F& z2Ap?L?7Dj7vM~&NaLionbT|eTj}}nG5A{%lmR?{Ekj0KGa2i}Xuae1gA&VE~`N9!L zHHgA4PzT#^oSAlH!V>5|s_pD$Nj6(zagG-vag<`bunHSs2m0=D!(C&Cj4mDpSxh0@ zf_bUKXBXMyXtS{fNw9P}SixEiV24VEHH=ueY(WlWF$*{fmn@x5#}M!kArd@7gDQA~ zWGDn=F|Y{8VsCH)vX~f<#jwgCi<#? z>%c{5q#J&c#X4pIS#0pT;U`(l1VKZWO9L)gq;9bZwtk%;i%GD=2FbPfWd(R)7{i4u zW-terI&CWm#E|TLI(LbSfh=YrOULSN_Kt1aGL)mT9_4^xOaX2fhZq0~4pX%35n@0n zI8M>Bo8Qy;4HyOFF~%D$J1H7KfkP-UYB#r6uf_`adKnp`Hg4?(gT&`J`HYg!rivPoI&rWiU4nTOr5m=1hNv`FK2P_d@m;=^d zcaob5%mK^U5fBIic8DS%@C0lDK|r7f*c^g@zzVRF1Ob5zU>^%g!6*E6I6xch^GJOR z&&K?E2wRmp$%nkA_>B|(X_(CCs{$~c{La*W$O=vCSLg$D3f1rsl2&M_YSK^6f5?Zt zrt*yw`)Qb=W>9JcrvGPcmsfrF{l}v(k`H;!;v47mac_a4RzGq_O2tt5hP#m5Yxdqa zmyhJ-8hHB2*n#DD48K@bXp+7{A9_=$hKI1C{Upuv55pprg4a*JKNh$49%&mwD7r#$ zsr#)vm%eI|JxP!5zDTaoht}Q$ZPdJ3KCVHeFD#d*lnj<{co!LBwehs~=o%l@BA*a5 z`3Ey)$5THZ`Z(_*xv3axV`CdWx)@Vq%Nqh>46WEH;MIi0_!yfI5Fx3q`2;k2r*RO03?8wA z6#+3w#70@_o!WTMd-TU6^+BEY5DzUxlcs?y^bs3{YIq1qeR`+Y zbg*%9xUt^pH4|){7skE)^iHoCVB>r+k~i#~G|^k3kHsid!$bahr}xmy5c1zU^|6-s z$O|>!Snt#ZSl+`eeALEzCmVYO&^H%jEM+(a#Fz>@l@ai2L1MgwZHtHzqa!A$(K*>z zh&4fUPJJd;8{qI}t4+Xq4P#hW*E=Vyb3TIMF6*575QYzASm*RPLxy!ueGtQkGU%Mz z2u3@6#Ha?Hv#%V7&Z&)H&^a-VLFbecf}+%J=$r_mb4JMW0H4mO4^g}a zEXw7mm|8xEiOy*pl_(O`nHZHQoq5$Vg9uxI5Fb?AJNDKBo*IBK5{8Z#rF}C`axTC zP!|gB<5KZ;xrlw)#drF`J?ieEwk~@ zTt735fk_*=J-+!k8Bb*&9Tp@WBxWY~;S65KHVDHG0=JD^-M)h@d&1as`YBO-O?@VU zodi+UHYI=56)Aan(fsSwPeCYMjZbCY3Syo;m3<$+FWPIzwDQC+Vr`cEcKiD5gTluI0{~SA={s-?to2#e-{~UWy z{s-@&Z+GGAx-XZNe$iIG(!4GF;g?;?R*|=r)#xy*=8Zh97iabD-S5CTN_mF^W#!Ek zA+j22wjOJ9x6;#U?fmS|KNMQ6@w>{t7$0P zvcA@juM5jQ)zM4h> ztM&P1|6I`4YCUd4?!?O|w^=^y_&#~ikAvhf6`77rhvlv7e9POiJom8t(^OgBi;Ob^>+?Ol;d0yekDINYzF&?B z*7I$xK6R?rVK*q&i%Bzna_}3A6^rt^>f8%EMsAG{R zTuqHyQxnzeol{?=TccG=O~qvE51H2YYv`e99;a^;-U;fPlG3l!WxR&a@?x}>r|mJQ z#jT~tXv5(H_$}POOYA)(6DCggI(vZqKJLX5D-Vw2Gn_p@KbU*5R7(Zb&mIWManIVg zaTfa(T|F)++nqE1+FTGir2u6Ax8Lp$%Ek}v8k5Z3^sTEtNzG%A)p#W-3>;CLyZwav zO>W=_Hyt?;G{U{1vT{Sv2&GWJ&(y%I+ADuPu6h;)X1VF`fuJn+_zyoEAC#p`)f3@B zf$9;rsmE32KUtPcHytq$l<6+mySE@HQ<17Cmsd?CGb=4nI(I;}jfCa4~*& zmnwf!YHGnQoTYFK$(2v%@zVt+?{*(6-}?NC6VGogKjto-JPFCGSn`S4*X*?%R6aXq zIeO~zTPM-!0?XZV_q-W2yylHPbKT1)A|-DN`6I3joTJQGWWMU;f`zk2()j`lj_x_W zCMc!m;p2ObEzH+nEw5E_RbFIdUdq+4tw{|^t{MLDwk0Wfh-U2uCl(rx8lWG_6%jbO z&~VfM{c^5|ka|R+d1|{N@l(2gmpmwZyrjqxw*9J{5J4B)_QE%k)JxbRbQ?{=l3z$z z=Hkg!O8E)o{W&r-r7Jay2SpDeepsRwOx{ghi4wOIRd2vxG&Wvyre!c6JgL3C~W#vV>7RQl3u2ni`X^rp6>Jnx|h0YvK~tq)Ax2Y>%{GS{z`qDkrC! ztrfj@RD3eX+Ihp*UtSkzt-JiGBL^0TSgW>g6oY&4-mR^vIcBj|r78}qwdluE?ica{E3%3=FbXOh15(+8AH?EHTJh*7lIjehEt@BbD z;|Juc?s_c2YQ63$}DwUp2B@=aZwXxn(^q)-Ung z@t<_{)YcSQWA>EoPO!%9`1I%D&)?3r!iU#IUK;OLvhn_?ePy5I1X^p6 z*Sh>DetE@ek1RI1 zte3^A(9NrUxYcTHzoBe@9#GVe9mN4JoJJJ>k&5oqJO4;UH#V5SHyZmM-Z944^^OsD z>l3L&_iG~ey;SKG6C(Gss?p4iYX#Vpam1 z;DirH@d#f>Kfd}{J%@gq`g_+uPcMR2y1rIcR4RB(vFRo+<$T7sNh+YC;qF=2-b_9` zG0V(+c$=haHLqG=5lnTd?z_>CuRd1Kq2H$d-u2JJ+wdZs_HD#hJLB8@F}@9JX>2CF z1355EnC3F+ptyFVs6E}2n{la;Z&fjFLi`I9frt(lzPkB61WE3LUFuZ*OS z+@)j3E>Q`nLojn{1T#=lI^*}~@uNi6?3!sjVX&n3#}Bcvq2BEGPn3UoeaHx9`m#Ve zCYjwS7?~1K2pZ?r9Q^l)tXrz{|6hA&7aB(u#qm4Yu`#w*-i*-%{84(`L**?2oc4I~S8*E)0LaP;qDJp7qmdv(vWR5ILND zdGcrUO~=$XC#L8NjukQT)U80rZ04UYVx33l2H*R;uVe5+$GIQO4(Cuj32l5*y=HVa z_sjg;ub)Swqc{HiJsZv4zZ{6#y=q8jHdDd9c1m@*lTLl~8srtLb11lH@sRA?L`Uxl z?q2LcYq=%4zj~LwKiQ&|cX@kjvif~H`3AjnBYd6p(L(xYQTo7Jjrlo(rf`0Js%H9H zqv>THj4S#0f?u`SRjQ>PpK7VCsWuzQjg953oj%oOBj$MiSi+}TdXegQfnI1=RJ9zC zKekh9vWRN4k;?G`{qqp%x}<7lT#n;Psa8hO&vKMjtrt~Pwcc>WRV!oUsh3o(oP<$1 z2_;qQ&8DkbHR*AlbXT?d>bRm3cqTdM~wK1 z8B*=~RLykzjRZ@BaV3PfK(>#J%K@?`=?T$Hd{Ozvv=GJ%`g?in z1~QYZKvv6s+b2{D@gy1d^Db5J31X|}Z_)gxG(V*I8#RBE=0C0Zo5|<#oKi^+kIl!g zhfff7>=&pI!yr;3RkroB?gctyN$UYy?}ucCZ`FfWzQ%Z~{CFUIZt> zYv2rMD~7AUAlL}Dg6&|pBvm8N`mFHC+vX)P;@P7gZ{^?Tjm_urc>E_Kg6;`BR?vLz zd-!eRB>fJ!Yn(G!!{gB75b+)OZxT7LQE^k{=D78tl^V(n^oREJeALI=RO;|j<_Ptv zl*wBkJY|MxALp3Qz~^*JLUK}B1G$_v_2OhZ4)uyrw@W*FwauvGQ>5;O0q`g|CaD@) zmaD&_y6UNqicx} Z*51bZJdEw?O5&?&wHYUQ{>xqk{{e-AbB6!` literal 0 HcmV?d00001 diff --git a/doc/img/aaronia_http_tx.jpg b/doc/img/aaronia_http_tx.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0a9f3a82da07f8f446c611e20d7c6c963f6413b GIT binary patch literal 22984 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 z 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 literal 0 HcmV?d00001 diff --git a/doc/img/aaronia_http_tx_iqmod.jpg b/doc/img/aaronia_http_tx_iqmod.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf08eda3dc2371b33b9f178ff08b889ac23ba05e GIT binary patch literal 17441 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 #include #include +#include #include "SWGDeviceSettings.h" #include "SWGDeviceState.h" @@ -32,18 +33,23 @@ #include "dsp/dspengine.h" #include "device/deviceapi.h" +#include "aaroniartsaoutputworker.h" #include "aaroniartsaoutput.h" MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgConfigureAaroniaRTSAOutput, Message) MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgStartStop, Message) MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgReportSampleRateAndFrequency, Message) +MESSAGE_CLASS_DEFINITION(AaroniaRTSAOutput::MsgSetStatus, Message) AaroniaRTSAOutput::AaroniaRTSAOutput(DeviceAPI *deviceAPI) : m_deviceAPI(deviceAPI), m_settings(), m_centerFrequency(0), m_sampleRate(48000), - m_deviceDescription("AaroniaRTSAOutput") + m_deviceDescription("AaroniaRTSAOutput"), + m_worker(nullptr), + m_workerThread(nullptr), + m_running(false) { m_sampleSourceFifo.resize(SampleSourceFifo::getSizePolicy(m_sampleRate)); m_deviceAPI->setNbSinkStreams(1); @@ -80,13 +86,53 @@ void AaroniaRTSAOutput::init() bool AaroniaRTSAOutput::start() { + QMutexLocker mutexLocker(&m_mutex); + + if (m_running) { + return true; + } + qDebug() << "AaroniaRTSAOutput::start"; + + m_workerThread = new QThread(); + m_worker = new AaroniaRTSAOutputWorker(&m_sampleSourceFifo); + m_worker->moveToThread(m_workerThread); + + QObject::connect(m_workerThread, &QThread::started, m_worker, &AaroniaRTSAOutputWorker::startWork); + QObject::connect(m_workerThread, &QThread::finished, m_worker, &QObject::deleteLater); + QObject::connect(m_workerThread, &QThread::finished, m_workerThread, &QThread::deleteLater); + QObject::connect(m_worker, &AaroniaRTSAOutputWorker::updateStatus, this, &AaroniaRTSAOutput::setWorkerStatus); + + m_workerThread->start(); + m_running = true; + + mutexLocker.unlock(); + applySettings(m_settings, QList(), true); + + qDebug("AaroniaRTSAOutput::start: started"); return true; } + void AaroniaRTSAOutput::stop() { + QMutexLocker mutexLocker(&m_mutex); + + if (!m_running) { + return; + } + qDebug() << "AaroniaRTSAOutput::stop"; + m_running = false; + + if (m_workerThread) + { + m_worker->stopWork(); + m_workerThread->quit(); + m_workerThread->wait(); + m_worker = nullptr; + m_workerThread = nullptr; + } } QByteArray AaroniaRTSAOutput::serialize() const @@ -165,6 +211,13 @@ void AaroniaRTSAOutput::setCenterFrequency(qint64 centerFrequency) } } +void AaroniaRTSAOutput::setWorkerStatus(int status) +{ + if (m_guiMessageQueue) { + m_guiMessageQueue->push(MsgSetStatus::create(status)); + } +} + bool AaroniaRTSAOutput::handleMessage(const Message& message) { if (DSPSignalNotification::match(message)) @@ -206,13 +259,48 @@ bool AaroniaRTSAOutput::handleMessage(const Message& message) } } +int AaroniaRTSAOutput::getStatus() const +{ + // TODO + // if (m_aaroniaRTSAWorker) { + // return m_aaroniaRTSAWorker->getStatus(); + // } else { + return 0; + // } +} + void AaroniaRTSAOutput::applySettings(const AaroniaRTSAOutputSettings& settings, const QList& settingsKeys, bool force) { qDebug() << "AaroniaRTSAOutput::applySettings: force:" << force << settings.getDebugString(settingsKeys, force); QMutexLocker mutexLocker(&m_mutex); std::ostringstream os; - QString remoteAddress; QList reverseAPIKeys; + bool forwardChangeToDSP = false; + + if (settingsKeys.contains("centerFrequency") || force) + { + if (m_worker) { + m_worker->setCenterFrequency(settings.m_centerFrequency); + } + + forwardChangeToDSP = true; + } + + if (settingsKeys.contains("sampleRate") || force) + { + if (m_worker) { + m_worker->setSampleRate(settings.m_sampleRate); + } + + forwardChangeToDSP = true; + } + + if (settingsKeys.contains("serverAddress") || force) + { + if (m_worker) { + m_worker->setServerAddress(settings.m_serverAddress); + } + } if (settingsKeys.contains("useReverseAPI")) { @@ -223,13 +311,17 @@ void AaroniaRTSAOutput::applySettings(const AaroniaRTSAOutputSettings& settings, webapiReverseSendSettings(settingsKeys, settings, fullUpdate || force); } + if (forwardChangeToDSP) + { + DSPSignalNotification *notif = new DSPSignalNotification(settings.m_sampleRate, settings.m_centerFrequency); + m_deviceAPI->getDeviceEngineInputMessageQueue()->push(notif); + } + if (force) { m_settings = settings; } else { m_settings.applySettings(settingsKeys, settings); } - - m_remoteAddress = remoteAddress; } int AaroniaRTSAOutput::webapiRunGet( @@ -299,6 +391,15 @@ void AaroniaRTSAOutput::webapiUpdateDeviceSettings( const QStringList& deviceSettingsKeys, SWGSDRangel::SWGDeviceSettings& response) { + if (deviceSettingsKeys.contains("centerFrequency")) { + settings.m_centerFrequency = response.getAaroniaRtsaOutputSettings()->getCenterFrequency(); + } + if (deviceSettingsKeys.contains("sampleRate")) { + settings.m_sampleRate = response.getAaroniaRtsaOutputSettings()->getSampleRate(); + } + if (deviceSettingsKeys.contains("serverAddress")) { + settings.m_serverAddress = *response.getAaroniaRtsaOutputSettings()->getServerAddress(); + } if (deviceSettingsKeys.contains("useReverseAPI")) { settings.m_useReverseAPI = response.getAaroniaRtsaOutputSettings()->getUseReverseApi() != 0; } @@ -315,6 +416,15 @@ void AaroniaRTSAOutput::webapiUpdateDeviceSettings( void AaroniaRTSAOutput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings& response, const AaroniaRTSAOutputSettings& settings) { + response.getAaroniaRtsaOutputSettings()->setCenterFrequency(settings.m_centerFrequency); + response.getAaroniaRtsaOutputSettings()->setSampleRate(settings.m_sampleRate); + + if (response.getAaroniaRtsaOutputSettings()->getServerAddress()) { + *response.getAaroniaRtsaOutputSettings()->getServerAddress() = settings.m_serverAddress; + } else { + response.getAaroniaRtsaOutputSettings()->setServerAddress(new QString(settings.m_serverAddress)); + } + response.getAaroniaRtsaOutputSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); if (response.getAaroniaRtsaOutputSettings()->getReverseApiAddress()) { @@ -340,8 +450,7 @@ int AaroniaRTSAOutput::webapiReportGet( void AaroniaRTSAOutput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response) { - response.getAaroniaRtsaOutputReport()->setCenterFrequency(m_centerFrequency); - response.getAaroniaRtsaOutputReport()->setSampleRate(m_sampleRate); + response.getAaroniaRtsaOutputReport()->setStatus(getStatus()); } void AaroniaRTSAOutput::webapiReverseSendSettings(const QList& deviceSettingsKeys, const AaroniaRTSAOutputSettings& settings, bool force) diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutput.h b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutput.h index 913c58ec5..93962443a 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutput.h +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutput.h @@ -15,8 +15,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_LOCALOUTPUT_H -#define INCLUDE_LOCALOUTPUT_H +#ifndef INCLUDE_AARONIARTSAOUTPUT_H +#define INCLUDE_AARONIARTSAOUTPUT_H #include #include @@ -34,6 +34,8 @@ class QNetworkAccessManager; class QNetworkReply; class DeviceAPI; +class QThread; +class AaroniaRTSAOutputWorker; class AaroniaRTSAOutput : public DeviceSampleSink { Q_OBJECT @@ -104,6 +106,25 @@ public: { } }; + class MsgSetStatus : public Message { + MESSAGE_CLASS_DECLARATION + + public: + int getStatus() const { return m_status; } + + static MsgSetStatus* create(int status) { + return new MsgSetStatus(status); + } + + protected: + int m_status; + + MsgSetStatus(int status) : + Message(), + m_status(status) + { } + }; + AaroniaRTSAOutput(DeviceAPI *deviceAPI); virtual ~AaroniaRTSAOutput(); virtual void destroy(); @@ -163,11 +184,14 @@ private: AaroniaRTSAOutputSettings m_settings; qint64 m_centerFrequency; int m_sampleRate; - QString m_remoteAddress; QString m_deviceDescription; QNetworkAccessManager *m_networkManager; QNetworkRequest m_networkRequest; + AaroniaRTSAOutputWorker *m_worker; + QThread *m_workerThread; + bool m_running; + int getStatus() const; void applySettings(const AaroniaRTSAOutputSettings& settings, const QList& settingsKeys, bool force = false); void webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response); void webapiReverseSendSettings(const QList& deviceSettingsKeys, const AaroniaRTSAOutputSettings& settings, bool force); @@ -175,6 +199,7 @@ private: private slots: void networkManagerFinished(QNetworkReply *reply); + void setWorkerStatus(int status); }; -#endif // INCLUDE_LOCALOUTPUT_H +#endif // INCLUDE_AARONIARTSAOUTPUT_H diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.cpp b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.cpp index 074c88555..301143dc0 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.cpp +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.cpp @@ -62,10 +62,26 @@ AaroniaRTSAOutputGui::AaroniaRTSAOutputGui(DeviceUISet *deviceUISet, QWidget* pa m_paletteGreenText.setColor(QPalette::WindowText, Qt::green); m_paletteWhiteText.setColor(QPalette::WindowText, Qt::white); + m_statusTooltips.push_back("Idle"); // 0 + m_statusTooltips.push_back("Unstable"); // 1 + m_statusTooltips.push_back("Connected"); // 2 + m_statusTooltips.push_back("Error"); // 3 + m_statusTooltips.push_back("Disconnected"); // 4 + + m_statusColors.push_back("gray"); // Idle + m_statusColors.push_back("rgb(232, 212, 35)"); // Unstable (yellow) + m_statusColors.push_back("rgb(35, 138, 35)"); // Connected (green) + m_statusColors.push_back("rgb(232, 85, 85)"); // Error (red) + m_statusColors.push_back("rgb(232, 85, 232)"); // Disconnected (magenta) + ui->setupUi(getContents()); sizeToContents(); getContents()->setStyleSheet("#AaroniaRTSAOutputGui { background-color: rgb(64, 64, 64); }"); - m_helpURL = "plugins/samplesink/localoutput/readme.md"; + m_helpURL = "plugins/samplesink/aaroniartsaoutput/readme.md"; + ui->centerFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->centerFrequency->setValueRange(9, 0, 999999999); + ui->sampleRate->setColorMapper(ColorMapper(ColorMapper::GrayGreenYellow)); + ui->sampleRate->setValueRange(7, 2000U, 8000000U); connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(openDeviceSettingsDialog(const QPoint &))); @@ -168,6 +184,28 @@ bool AaroniaRTSAOutputGui::handleMessage(const Message& message) return true; } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) message; + m_streamSampleRate = notif.getSampleRate(); + m_streamCenterFrequency = notif.getCenterFrequency(); + qDebug("AaroniaRTSAOutputGui::handleInputMessages: DSPSignalNotification: SampleRate:%d, CenterFrequency:%llu", + notif.getSampleRate(), + notif.getCenterFrequency()); + updateSampleRateAndFrequency(); + + return true; + } + else if (AaroniaRTSAOutput::MsgSetStatus::match(message)) + { + qDebug("AaroniaRTSAOutputGui::handleMessage: MsgSetStatus"); + AaroniaRTSAOutput::MsgSetStatus& notif = (AaroniaRTSAOutput::MsgSetStatus&) message; + int status = notif.getStatus(); + ui->statusIndicator->setToolTip(m_statusTooltips[status]); + ui->statusIndicator->setStyleSheet("QLabel { background-color: " + + m_statusColors[status] + "; border-radius: 7px; }"); + return true; + } else { return false; @@ -209,13 +247,12 @@ void AaroniaRTSAOutputGui::handleInputMessages() } } -void AaroniaRTSAOutputGui::updateSampleRateAndFrequency() -{ +void AaroniaRTSAOutputGui::updateSampleRateAndFrequency(){ m_deviceUISet->getSpectrum()->setSampleRate(m_streamSampleRate); m_deviceUISet->getSpectrum()->setCenterFrequency(m_streamCenterFrequency); ui->deviceRateText->setText(tr("%1k").arg((float)m_streamSampleRate / 1000)); blockApplySettings(true); - ui->centerFrequency->setText(QString("%L1").arg(m_streamCenterFrequency / 1000)); + ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); blockApplySettings(false); } @@ -223,8 +260,10 @@ void AaroniaRTSAOutputGui::displaySettings() { blockApplySettings(true); - ui->centerFrequency->setText(QString("%L1").arg(m_streamCenterFrequency / 1000)); + ui->centerFrequency->setValue(m_settings.m_centerFrequency / 1000); + ui->sampleRate->setValue(m_settings.m_sampleRate); ui->deviceRateText->setText(tr("%1k").arg(m_streamSampleRate / 1000.0)); + ui->serverAddress->setText(m_settings.m_serverAddress); blockApplySettings(false); } @@ -245,6 +284,40 @@ void AaroniaRTSAOutputGui::on_startStop_toggled(bool checked) } } +void AaroniaRTSAOutputGui::on_centerFrequency_changed(quint64 value) +{ + m_settings.m_centerFrequency = value * 1000; + m_settingsKeys.append("centerFrequency"); + sendSettings(); +} + +void AaroniaRTSAOutputGui::on_sampleRate_changed(quint64 value) +{ + m_settings.m_sampleRate = value; + m_settingsKeys.append("sampleRate"); + sendSettings(); +} + +void AaroniaRTSAOutputGui::on_serverAddress_returnPressed() +{ + on_serverAddressApplyButton_clicked(); +} + +void AaroniaRTSAOutputGui::on_serverAddressApplyButton_clicked() +{ + QString serverAddress = ui->serverAddress->text(); + QUrl url(serverAddress); + + if (QStringList{"ws", "wss", "http", "https"}.contains(url.scheme())) { + m_settings.m_serverAddress = QString("%1:%2").arg(url.host()).arg(url.port()); + } else { + m_settings.m_serverAddress = serverAddress; + } + + m_settingsKeys.append("serverAddress"); + sendSettings(); +} + void AaroniaRTSAOutputGui::updateHardware() { if (m_doApplySettings) @@ -320,4 +393,8 @@ void AaroniaRTSAOutputGui::openDeviceSettingsDialog(const QPoint& p) void AaroniaRTSAOutputGui::makeUIConnections() { QObject::connect(ui->startStop, &ButtonSwitch::toggled, this, &AaroniaRTSAOutputGui::on_startStop_toggled); + QObject::connect(ui->centerFrequency, &ValueDial::changed, this, &AaroniaRTSAOutputGui::on_centerFrequency_changed); + QObject::connect(ui->sampleRate, &ValueDial::changed, this, &AaroniaRTSAOutputGui::on_sampleRate_changed); + QObject::connect(ui->serverAddress, &QLineEdit::returnPressed, this, &AaroniaRTSAOutputGui::on_serverAddress_returnPressed); + QObject::connect(ui->serverAddressApplyButton, &QPushButton::clicked, this, &AaroniaRTSAOutputGui::on_serverAddressApplyButton_clicked); } diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.h b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.h index 5b1b1805a..9a8ca6a4a 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.h +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.h @@ -15,8 +15,8 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_LOCALOUTPUTGUI_H -#define INCLUDE_LOCALOUTPUTGUI_H +#ifndef INCLUDE_AARONIARTSAOUTPUTGUI_H +#define INCLUDE_AARONIARTSAOUTPUTGUI_H #include #include @@ -70,6 +70,9 @@ private: QPalette m_paletteGreenText; QPalette m_paletteWhiteText; + std::vector m_statusColors; + std::vector m_statusTooltips; + void blockApplySettings(bool block); void displaySettings(); void sendSettings(); @@ -80,9 +83,13 @@ private: private slots: void handleInputMessages(); void on_startStop_toggled(bool checked); + void on_centerFrequency_changed(quint64 value); + void on_sampleRate_changed(quint64 value); + void on_serverAddress_returnPressed(); + void on_serverAddressApplyButton_clicked(); void updateHardware(); void updateStatus(); void openDeviceSettingsDialog(const QPoint& p); }; -#endif // INCLUDE_LOCALOUTPUTGUI_H +#endif // INCLUDE_AARONIARTSAOUTPUTGUI_H diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.ui b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.ui index 5238591ef..adcc68316 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.ui +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputgui.ui @@ -7,7 +7,7 @@ 0 0 360 - 47 + 130 @@ -19,13 +19,13 @@ 360 - 47 + 130 380 - 68 + 130 @@ -112,24 +112,36 @@ - + + + + 0 + 0 + + - 170 - 0 + 32 + 16 - Liberation Sans + Liberation Mono 16 + 50 + false + false - - 10,000,000,000 + + PointingHandCursor - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + Qt::StrongFocus + + + Tuner center frequency in kHz @@ -142,7 +154,7 @@ - Hz + kHz Qt::AlignCenter @@ -164,6 +176,130 @@ + + + + 2 + + + + + SR + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + 50 + false + false + + + + PointingHandCursor + + + Device sample rate + + + + + + + S/s + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Addr + + + + + + + Server address + + + 127.0.0.1:8073 + + + + + + + + 0 + 0 + + + + + 14 + 14 + + + + Idle + + + QLabel { background-color: gray; border-radius: 7px; } + + + + + + + + + + + 30 + 16777215 + + + + Set + + + + + @@ -172,6 +308,12 @@ QToolButton
gui/buttonswitch.h
+ + ValueDial + QWidget +
gui/valuedial.h
+ 1 +
diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.cpp b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.cpp index 727c0a398..49ccee076 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.cpp +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.cpp @@ -30,8 +30,8 @@ const PluginDescriptor AaroniaRTSAOutputPlugin::m_pluginDescriptor = { QStringLiteral("AaroniaRTSAOutput"), - QStringLiteral("Local device output"), - QStringLiteral("7.8.2"), + QStringLiteral("AaroniaRTSA output"), + QStringLiteral("7.14.0"), QStringLiteral("(c) Edouard Griffiths, F4EXB"), QStringLiteral("https://github.com/f4exb/sdrangel"), true, @@ -39,7 +39,7 @@ const PluginDescriptor AaroniaRTSAOutputPlugin::m_pluginDescriptor = { }; static constexpr const char* const m_hardwareID = "AaroniaRTSAOutput"; -static constexpr const char* const m_deviceTypeID = LOCALOUTPUT_DEVICE_TYPE_ID; +static constexpr const char* const m_deviceTypeID = AARONIARTSAOUTPUT_DEVICE_TYPE_ID; AaroniaRTSAOutputPlugin::AaroniaRTSAOutputPlugin(QObject* parent) : QObject(parent) diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.h b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.h index aa6ad1072..404095277 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.h +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputplugin.h @@ -15,20 +15,20 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef INCLUDE_LOCALOUTPUTPLUGIN_H -#define INCLUDE_LOCALOUTPUTPLUGIN_H +#ifndef INCLUDE_AARONIARTSAOUTPUTPLUGIN_H +#define INCLUDE_AARONIARTSAOUTPUTPLUGIN_H #include #include "plugin/plugininterface.h" -#define LOCALOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesink.localoutput" +#define AARONIARTSAOUTPUT_DEVICE_TYPE_ID "sdrangel.samplesink.aaroniartsaoutput" class PluginAPI; class AaroniaRTSAOutputPlugin : public QObject, public PluginInterface { Q_OBJECT Q_INTERFACES(PluginInterface) - Q_PLUGIN_METADATA(IID LOCALOUTPUT_DEVICE_TYPE_ID) + Q_PLUGIN_METADATA(IID AARONIARTSAOUTPUT_DEVICE_TYPE_ID) public: explicit AaroniaRTSAOutputPlugin(QObject* parent = nullptr); @@ -49,4 +49,4 @@ private: static const PluginDescriptor m_pluginDescriptor; }; -#endif // INCLUDE_LOCALOUTPUTPLUGIN_H +#endif // INCLUDE_AARONIARTSAOUTPUTPLUGIN_H diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.cpp b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.cpp index 83886eb6d..099b5df14 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.cpp +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.cpp @@ -25,6 +25,9 @@ AaroniaRTSAOutputSettings::AaroniaRTSAOutputSettings() void AaroniaRTSAOutputSettings::resetToDefaults() { + m_centerFrequency = 433200000; + m_sampleRate = 100000; + m_serverAddress = "127.0.0.1:5550"; m_useReverseAPI = false; m_reverseAPIAddress = "127.0.0.1"; m_reverseAPIPort = 8888; @@ -35,9 +38,12 @@ QByteArray AaroniaRTSAOutputSettings::serialize() const { SimpleSerializer s(1); - s.writeString(4, m_reverseAPIAddress); - s.writeU32(5, m_reverseAPIPort); - s.writeU32(6, m_reverseAPIDeviceIndex); + s.writeU64(1, m_centerFrequency); + s.writeString(2, m_serverAddress); + s.writeS32(3, m_sampleRate); + s.writeString(20, m_reverseAPIAddress); + s.writeU32(21, m_reverseAPIPort); + s.writeU32(22, m_reverseAPIDeviceIndex); return s.final(); } @@ -56,8 +62,11 @@ bool AaroniaRTSAOutputSettings::deserialize(const QByteArray& data) { quint32 uintval; - d.readString(4, &m_reverseAPIAddress, "127.0.0.1"); - d.readU32(5, &uintval, 0); + d.readU64(1, &m_centerFrequency, 433200000); + d.readString(2, &m_serverAddress, "127.0.0.1:5550"); + d.readS32(3, &m_sampleRate, 100000); + d.readString(20, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(21, &uintval, 0); if ((uintval > 1023) && (uintval < 65535)) { m_reverseAPIPort = uintval; @@ -65,7 +74,7 @@ bool AaroniaRTSAOutputSettings::deserialize(const QByteArray& data) m_reverseAPIPort = 8888; } - d.readU32(6, &uintval, 0); + d.readU32(22, &uintval, 0); m_reverseAPIDeviceIndex = uintval > 99 ? 99 : uintval; return true; @@ -79,6 +88,15 @@ bool AaroniaRTSAOutputSettings::deserialize(const QByteArray& data) void AaroniaRTSAOutputSettings::applySettings(const QStringList& settingsKeys, const AaroniaRTSAOutputSettings& settings) { + if (settingsKeys.contains("centerFrequency")) { + m_centerFrequency = settings.m_centerFrequency; + } + if (settingsKeys.contains("sampleRate")) { + m_sampleRate = settings.m_sampleRate; + } + if (settingsKeys.contains("serverAddress")) { + m_serverAddress = settings.m_serverAddress; + } if (settingsKeys.contains("useReverseAPI")) { m_useReverseAPI = settings.m_useReverseAPI; } @@ -97,6 +115,15 @@ QString AaroniaRTSAOutputSettings::getDebugString(const QStringList& settingsKey { std::ostringstream ostr; + if (settingsKeys.contains("centerFrequency") || force) { + ostr << " m_centerFrequency: " << m_centerFrequency; + } + if (settingsKeys.contains("sampleRate") || force) { + ostr << " m_sampleRate: " << m_sampleRate; + } + if (settingsKeys.contains("serverAddress") || force) { + ostr << " m_serverAddress: " << m_serverAddress.toStdString(); + } if (settingsKeys.contains("useReverseAPI") || force) { ostr << " m_useReverseAPI: " << m_useReverseAPI; } diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.h b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.h index 23d326845..d36af2697 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.h +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputsettings.h @@ -15,13 +15,28 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// -#ifndef PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ -#define PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ +#ifndef PLUGINS_AARONIARTSAOUTPUTSETTINGS_H_ +#define PLUGINS_AARONIARTSAOUTPUTSETTINGS_H_ #include #include -struct AaroniaRTSAOutputSettings { +struct AaroniaRTSAOutputSettings +{ + enum ConnectionStatus + { + ConnectionIdle, // 0 - gray + ConnectionUnstable, // 1 - yellow + ConnectionOK, // 2 - green + ConnectionError, // 3 - red + ConnectionDisconnected // 4 - magenta + }; + + quint64 m_centerFrequency; + int m_sampleRate; + QString m_serverAddress; + + bool m_useReverseAPI; QString m_reverseAPIAddress; uint16_t m_reverseAPIPort; @@ -35,4 +50,4 @@ struct AaroniaRTSAOutputSettings { QString getDebugString(const QStringList& settingsKeys, bool force=false) const; }; -#endif /* PLUGINS_SAMPLESINK_LOCALOUTPUT_LOCALOUTPUTSETTINGS_H_ */ +#endif /* PLUGINS_AARONIARTSAOUTPUTSETTINGS_H_ */ diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputwebapiadapter.h b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputwebapiadapter.h index d9f91c481..c4540b7d8 100644 --- a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputwebapiadapter.h +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputwebapiadapter.h @@ -18,6 +18,9 @@ // along with this program. If not, see . // /////////////////////////////////////////////////////////////////////////////////// +#ifndef PLUGINS_AARONIARTSAOUTPUTWEBAPIADAPTER_H_ +#define PLUGINS_AARONIARTSAOUTPUTWEBAPIADAPTER_H_ + #include "device/devicewebapiadapter.h" #include "aaroniartsaoutputsettings.h" @@ -42,3 +45,5 @@ public: private: AaroniaRTSAOutputSettings m_settings; }; + +#endif // PLUGINS_AARONIARTSAOUTPUTWEBAPIADAPTER_H_ diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.cpp b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.cpp new file mode 100644 index 000000000..6ab25633f --- /dev/null +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.cpp @@ -0,0 +1,183 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include "aaroniartsaoutputsettings.h" +#include "aaroniartsaoutputworker.h" + +AaroniaRTSAOutputWorker::AaroniaRTSAOutputWorker(SampleSourceFifo* sampleFifo, QObject* parent) : + QObject(parent), + m_running(false), + m_sampleFifo(sampleFifo), + m_sampleRate(100000), + m_packetsPerSecond(10), + m_samplesArrayInt16(nullptr) +{ + m_samplesPerPacket = m_sampleRate / m_packetsPerSecond; + m_networkAccessManager = new QNetworkAccessManager(this); + m_timer = new QTimer(this); + m_timer->setTimerType(Qt::PreciseTimer); + m_centerFrequency = 145000000; +} + +AaroniaRTSAOutputWorker::~AaroniaRTSAOutputWorker() +{ + if (m_running) { + stopWork(); + } +} + +void AaroniaRTSAOutputWorker::startWork() +{ + qDebug("aroniaRTSAOutputWorker::startWork"); + m_samplesPerPacket = m_sampleRate / m_packetsPerSecond; + m_sampleResendTime = 1000 / (m_sampleRate / m_samplesPerPacket) ; + m_streamStartTime = ( QDateTime::currentDateTime().currentMSecsSinceEpoch() ); + m_lastPacketEnd = m_streamStartTime / 1000.0; + m_sumSamples = 0; + + connect(m_timer, SIGNAL(timeout()), this, SLOT(onGeneratePacket())); + qDebug("AaroniaRTSAOutputWorker::startWork: m_sampleResendTime: %f", m_sampleResendTime); + m_timer->start(m_sampleResendTime); //send period + m_running = true; +} + +void AaroniaRTSAOutputWorker::stopWork() +{ + qDebug("aroniaRTSAOutputWorker::stopWork"); + m_running = false; + m_status = AaroniaRTSAOutputSettings::ConnectionIdle; + emit updateStatus(m_status); + disconnect(m_timer, SIGNAL(timeout()), this, SLOT(onGeneratePacket())); + m_timer->stop(); +} + +void AaroniaRTSAOutputWorker::setSampleRate(int sampleRate) +{ + qDebug("aroniaRTSAOutputWorker::setSampleRate: %d", sampleRate); + + if (sampleRate == m_sampleRate) { + return; + } + + m_samplesPerPacket = sampleRate / m_packetsPerSecond; + m_sampleResendTime = 1000 / (sampleRate / m_samplesPerPacket) ; + m_timer->start(m_sampleResendTime); //send period + m_sampleRate = sampleRate; +} + +void AaroniaRTSAOutputWorker::onGeneratePacket() +{ + double sampleTimeUS = 1000000.0 / m_sampleRate; + qint64 deltaT = QDateTime::currentDateTime().currentMSecsSinceEpoch(); + deltaT = deltaT - (m_lastPacketEnd*1000); + double ndiff = 1000*((double)deltaT + 1 ) / sampleTimeUS ; + double reawaketime = m_sampleResendTime - (sampleTimeUS*(ndiff - m_samplesPerPacket ))/1000 ; + // qDebug("AaroniaRTSAOutputWorker::onGeneratePacket: %f", reawaketime); + m_timer->setInterval( reawaketime ); + + double newStart = m_lastPacketEnd; + m_lastPacketEnd = newStart + ((m_samplesPerPacket + 1) * sampleTimeUS)/1000000 ; + + double timeOffset = 0.4; //put it into future + + buildSamples( newStart + timeOffset , m_lastPacketEnd + timeOffset); +} + +void AaroniaRTSAOutputWorker::buildSamples(double startTime, double stopTime) +{ + unsigned int iPart1Begin, iPart1End, iPart2Begin, iPart2End; + SampleVector& data = m_sampleFifo->getData(); + m_sampleFifo->read(m_samplesPerPacket, iPart1Begin, iPart1End, iPart2Begin, iPart2End); + + if (m_samplesArrayInt16 == nullptr) { + m_samplesArrayInt16 = new int16_t[2*m_samplesPerPacket]; + } + + if (iPart1Begin != iPart1End) { + callbackPart(m_samplesArrayInt16, data, iPart1Begin, iPart1End); + } + + if (iPart2Begin != iPart2End) { + callbackPart(&m_samplesArrayInt16[(iPart1End - iPart1Begin)*2], data, iPart2Begin, iPart2End); + } + + double startFrequency = m_centerFrequency - m_sampleRate/2; + double endFrequency = m_centerFrequency + m_sampleRate/2; + + QJsonDocument jdoc(QJsonObject({ + {"startTime", startTime }, + {"endTime" , stopTime }, + {"startFrequency", startFrequency }, + {"endFrequency" , endFrequency }, + {"minPower", -2}, + {"maxPower" , 2}, + {"sampleSize", 2}, + {"sampleDepth" , 1}, + {"payload", "iq"}, + {"format", "int16"}, + {"scale", 512.0}, + {"unit" , "volt"}, + {"samples" , 2*m_samplesPerPacket}, + })); + + postData(jdoc, m_samplesArrayInt16, 2*m_samplesPerPacket); +} + +void AaroniaRTSAOutputWorker::callbackPart(int16_t *buf, SampleVector& data, unsigned int iBegin, unsigned int iEnd) +{ + for (unsigned int j = 0, i = iBegin; i < iEnd; j++, i++) + { + buf[2*j] = data[i].m_real; + buf[2*j+1] = data[i].m_imag; + } +} + +void AaroniaRTSAOutputWorker::postData(QJsonDocument jdoc, int16_t *samplesArray, int nSamples) +{ + QUrl url(tr("http://%1/sample").arg(m_serverAddress)); + qDebug() << "AaroniaRTSAOutputWorker::postData:" << url; + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/json")); + QByteArray byteArray = jdoc.toJson(QJsonDocument::Compact); + byteArray.append(0x1e); + byteArray.append(QByteArray::fromRawData(reinterpret_cast(samplesArray), nSamples*sizeof(int16_t))); + QNetworkReply *networkReply = m_networkAccessManager->post(request, byteArray); + + connect(networkReply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(onError(QNetworkReply::NetworkError))); + connect(m_networkAccessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*))); +} + +void AaroniaRTSAOutputWorker::onError(QNetworkReply::NetworkError) +{ + QNetworkReply* nReply = qobject_cast( sender() ); + qDebug() << "AaroniaRTSAOutputWorker::onError: Network Error: " + nReply->errorString(); + m_timer->stop(); + m_status = AaroniaRTSAOutputSettings::ConnectionError; + emit updateStatus(m_status); +} + +void AaroniaRTSAOutputWorker::onFinished(QNetworkReply *reply) +{ + if ((m_status != AaroniaRTSAOutputSettings::ConnectionOK) && (reply->error() == QNetworkReply::NoError)) + { + m_status = AaroniaRTSAOutputSettings::ConnectionOK; + emit updateStatus(m_status); + } + + reply->deleteLater(); +} diff --git a/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.h b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.h new file mode 100644 index 000000000..8dec17583 --- /dev/null +++ b/plugins/samplesink/aaroniartsaoutput/aaroniartsaoutputworker.h @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef _AARONIARTSA_AARONIARTSAOUTPUTWORKER_H_ +#define _AARONIARTSA_AARONIARTSAOUTPUTWORKER_H_ + +#include + +#include "dsp/samplesourcefifo.h" +#include "util/message.h" + +#include +#include +#include +#include +#include +#include +#include "dsp/decimatorsfi.h" + +class AaroniaRTSAOutputWorker : public QObject { + Q_OBJECT +public: + enum TxFormat { + FLOAT32, + INT16, + ASCII + }; + + AaroniaRTSAOutputWorker(SampleSourceFifo* sampleFifo, QObject* parent = nullptr); + ~AaroniaRTSAOutputWorker(); + void startWork(); + void stopWork(); + int getStatus() const { return m_status; } + void setServerAddress(const QString& serverAddress) { m_serverAddress = serverAddress; } + void setCenterFrequency(quint64 centerFrequency) { m_centerFrequency = centerFrequency; } + void setSampleRate(int sampleRate); + +signals: + void updateStatus(int status); + +private: + volatile bool m_running; + QTimer *m_timer; + + SampleVector m_samplesBuf; + SampleSourceFifo* m_sampleFifo; + + QString m_serverAddress; + quint64 m_centerFrequency; + int m_sampleRate; + int m_status; //!< See GUI for status number detail + + QNetworkAccessManager *m_networkAccessManager; + int m_packetsPerSecond; + int m_samplesPerPacket; + TxFormat m_txFormat; + qint64 m_streamStartTime; + quint64 m_sumSamples; + long double m_lastPacketEnd; + double m_sampleResendTime; + int16_t *m_samplesArrayInt16; + + void buildSamples(double startTime, double stopTime); + void callbackPart(int16_t *buf, SampleVector& data, unsigned int iBegin, unsigned int iEnd); + void postData(QJsonDocument jdoc, int16_t *samplesArray, int nSamples); + +private slots: + void onGeneratePacket(); + void onError(QNetworkReply::NetworkError code); + void onFinished(QNetworkReply *); + +}; + +#endif // _AARONIARTSA_AARONIARTSAOUTPUTWORKER_H_ diff --git a/plugins/samplesink/aaroniartsaoutput/readme.md b/plugins/samplesink/aaroniartsaoutput/readme.md index 796ec7f2a..ee6d3a14a 100644 --- a/plugins/samplesink/aaroniartsaoutput/readme.md +++ b/plugins/samplesink/aaroniartsaoutput/readme.md @@ -1,14 +1,28 @@ -

Local output plugin

+

Aaronia RTSA output plugin

Introduction

-This output sample sink plugin sends its samples to a Local Source channel in another device set. +You can use this plugin to interface with a http server block in the Aaronia RTSA suite connected to a Spectran V6 device. It is assumed that you have prior knowledge of the Aaronia RTSA suite software and operation of the Spectran V6 RTSA (Real Time Spectrum Analyzer). However in this context there are some specificities i.e. it assumes that the "mission" (in RTSA suite terms) that is the equivalent of a "configuration" in SDRangel has a `HTTP Server` block followed by an `IQ Modulator` block. + +An example flow graph could be the following (Stram Debugger is optional): + +![Aaronia RTSA Tx flowgraph](../../../doc/img/aaronia_http_tx.jpg) + +You have to check the "Adapt Center Frequency" and "Adapt Sample Rate" options in the IQ modulator settings so that SDRangel can control center frequency and sample rate: + +![Aaronia RTSA Tx IQMod settings](../../../doc/img/aaronia_http_tx_iqmod.jpg) + +You can obviously run the RTSA suite and SDRangel on the same machine and connect via localhost but there are advantages on a split setup: + + - The workload can be split between RTSA suite and SDRangel on two different machines. RTSA suite has to perform the upsampling at a very high sample rate so this is demanding on CPU and latency. Often it is better to run it on its own dedicated machine. + + - You can have the RTSA suite run on a machine close to the Spectran. This is in fact mandatory due to the length of the USB cables. And you can run SDRangel on another machine (possibly quite more lightweight) anywhere on the network.

Interface

The top and bottom bars of the device window are described [here](../../../sdrgui/device/readme.md) -![SDR Local output plugin GUI](../../../doc/img/LocalOutput_plugin.png) +![Aaronia RTSA output plugin GUI](../../../doc/img/AaroniaRTSAOutput.png)

1: Start/Stop

@@ -17,10 +31,34 @@ Device start / stop button. - Blue triangle icon: device is ready and can be started - Green square icon: device is running and can be stopped -

2: Frequency

+

2: Stream sample rate

-This is the center frequency in Hz sent from the Local Source channel instance and corresponds to the center frequency of transmission. +This is the sample rate of the I/Q stream sent to RTSA suite. It should be equal to the value set in (4) -

3: Stream sample rate

+

3: Frequency

-Stream I/Q sample rate in kS/s +This is the center frequency to which set the IQ modulator center frequency. + +

4: Stream sample rate

+ +Sets the I/Q stream sample rate in S/s + +

5: Remote address and port

+ +This is the remote address and port of the HTTP server block in RTSA suite. The address has to be in the form of an IPv4 address. + +Press button (7) to validate your change. + +

6: Status indicator

+ +This ball can take the following colors depending on the status: + + * **Gray**: Idle + * **Yellow**: Unstable + * **Green**: Connected + * **Red**: Error + * **Magenta**: Disconnected + +

7: Set address

+ +When you change the address in (5) you have to push this button to validate the change. diff --git a/plugins/samplesource/aaroniartsainput/aaroniartsainput.cpp b/plugins/samplesource/aaroniartsainput/aaroniartsainput.cpp index 6b629e382..45def183a 100644 --- a/plugins/samplesource/aaroniartsainput/aaroniartsainput.cpp +++ b/plugins/samplesource/aaroniartsainput/aaroniartsainput.cpp @@ -282,7 +282,7 @@ bool AaroniaRTSAInput::applySettings(const AaroniaRTSAInputSettings& settings, c qDebug() << "AaroniaRTSAInput::applySettings: force: "<< force << settings.getDebugString(settingsKeys, force); if (settingsKeys.contains("serverAddress") || force) - { +{ emit setWorkerServerAddress(settings.m_serverAddress); } @@ -412,7 +412,7 @@ int AaroniaRTSAInput::webapiReportGet( QString& errorMessage) { (void) errorMessage; - response.setAaroniaSdrReport(new SWGSDRangel::SWGAaroniaRTSAReport()); + response.setAaroniaRtsaReport(new SWGSDRangel::SWGAaroniaRTSAReport()); response.getAirspyHfReport()->init(); webapiFormatDeviceReport(response); return 200; @@ -443,7 +443,7 @@ void AaroniaRTSAInput::webapiFormatDeviceSettings(SWGSDRangel::SWGDeviceSettings void AaroniaRTSAInput::webapiFormatDeviceReport(SWGSDRangel::SWGDeviceReport& response) { - response.getAaroniaSdrReport()->setStatus(getStatus()); + response.getAaroniaRtsaReport()->setStatus(getStatus()); } void AaroniaRTSAInput::webapiReverseSendSettings(const QList& deviceSettingsKeys, const AaroniaRTSAInputSettings& settings, bool force) diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index d8f711d77..ad20c5244 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -2100,18 +2100,28 @@ margin-bottom: 20px; }; defs.AaroniaRTSAOutputReport = { "properties" : { - "centerFrequency" : { + "status" : { "type" : "integer", - "format" : "int64" - }, - "sampleRate" : { - "type" : "integer" + "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n" } }, "description" : "AaroniaRTSAOutput" }; defs.AaroniaRTSAOutputSettings = { "properties" : { + "centerFrequency" : { + "type" : "integer", + "format" : "int64", + "description" : "Sets the center frequency (Hz) of the distant IQ demodulator" + }, + "sampleRate" : { + "type" : "integer", + "description" : "Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator" + }, + "serverAddress" : { + "type" : "string", + "description" : "Distant AaroniaRTSA instance URL or IPv4 address with port" + }, "useReverseAPI" : { "type" : "integer", "description" : "Synchronize with reverse API (1 for yes, 0 for no)" @@ -2132,7 +2142,7 @@ margin-bottom: 20px; "properties" : { "status" : { "type" : "integer", - "description" : "0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected" + "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n" } }, "description" : "AaroniaRTSA" @@ -5276,7 +5286,7 @@ margin-bottom: 20px; "xtrxMIMOReport" : { "$ref" : "#/definitions/XtrxMIMOReport" }, - "aaroniaSDRReport" : { + "AaroniaRTSAReport" : { "$ref" : "#/definitions/AaroniaRTSAReport" }, "aaroniaRTSAOutputReport" : { @@ -57561,7 +57571,7 @@ except ApiException as e:
- Generated 2023-04-10T20:01:50.318+02:00 + Generated 2023-04-22T13:14:49.587+02:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/AaroniaRTSA.yaml b/sdrbase/resources/webapi/doc/swagger/include/AaroniaRTSA.yaml index 92eeda2b0..78c339cea 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/AaroniaRTSA.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/AaroniaRTSA.yaml @@ -25,12 +25,28 @@ AaroniaRTSAReport: description: AaroniaRTSA properties: status: - description: 0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected type: integer + description: > + Connection to RTSA server status: + * 0 - Idle + * 1 - Unstable + * 2 - Connected + * 3 - Error + * 4 - Disconnected AaroniaRTSAOutputSettings: description: AaroniaRTSAOutput properties: + centerFrequency: + description: Sets the center frequency (Hz) of the distant IQ demodulator + type: integer + format: int64 + sampleRate: + description: Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator + type: integer + serverAddress: + description: Distant AaroniaRTSA instance URL or IPv4 address with port + type: string useReverseAPI: description: Synchronize with reverse API (1 for yes, 0 for no) type: integer @@ -44,8 +60,12 @@ AaroniaRTSAOutputSettings: AaroniaRTSAOutputReport: description: AaroniaRTSAOutput properties: - centerFrequency: - type: integer - format: int64 - sampleRate: + status: type: integer + description: > + Connection to RTSA server status: + * 0 - Idle + * 1 - Unstable + * 2 - Connected + * 3 - Error + * 4 - Disconnected diff --git a/sdrbase/resources/webapi/doc/swagger/include/DeviceReports.yaml b/sdrbase/resources/webapi/doc/swagger/include/DeviceReports.yaml index 65761733e..2327bb77e 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/DeviceReports.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/DeviceReports.yaml @@ -71,7 +71,7 @@ DeviceReport: $ref: "/doc/swagger/include/Xtrx.yaml#/XtrxOutputReport" xtrxMIMOReport: $ref: "/doc/swagger/include/Xtrx.yaml#/XtrxMIMOReport" - aaroniaSDRReport: + AaroniaRTSAReport: $ref: "/doc/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSAReport" aaroniaRTSAOutputReport: $ref: "/doc/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSAOutputReport" diff --git a/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml b/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml index 3caad794a..4512c9d78 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/GS232Controller.yaml @@ -50,7 +50,13 @@ GS232ControllerSettings: type: number format: float protocol: - description: (0 GS-232, 1 SPID rot2prog) + description: (0 GS-232, 1 SPID rot2prog, 2 rotcltd, 3 DFM) + type: integer + precision: + description: Precision of azimuth and elevation values + type: integer + coordinates: + description: (0 Az/El, 1 X/Y 85, 2 X/Y 30) type: integer title: type: string diff --git a/swagger/sdrangel/api/swagger/include/AaroniaRTSA.yaml b/swagger/sdrangel/api/swagger/include/AaroniaRTSA.yaml index 92eeda2b0..78c339cea 100644 --- a/swagger/sdrangel/api/swagger/include/AaroniaRTSA.yaml +++ b/swagger/sdrangel/api/swagger/include/AaroniaRTSA.yaml @@ -25,12 +25,28 @@ AaroniaRTSAReport: description: AaroniaRTSA properties: status: - description: 0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected type: integer + description: > + Connection to RTSA server status: + * 0 - Idle + * 1 - Unstable + * 2 - Connected + * 3 - Error + * 4 - Disconnected AaroniaRTSAOutputSettings: description: AaroniaRTSAOutput properties: + centerFrequency: + description: Sets the center frequency (Hz) of the distant IQ demodulator + type: integer + format: int64 + sampleRate: + description: Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator + type: integer + serverAddress: + description: Distant AaroniaRTSA instance URL or IPv4 address with port + type: string useReverseAPI: description: Synchronize with reverse API (1 for yes, 0 for no) type: integer @@ -44,8 +60,12 @@ AaroniaRTSAOutputSettings: AaroniaRTSAOutputReport: description: AaroniaRTSAOutput properties: - centerFrequency: - type: integer - format: int64 - sampleRate: + status: type: integer + description: > + Connection to RTSA server status: + * 0 - Idle + * 1 - Unstable + * 2 - Connected + * 3 - Error + * 4 - Disconnected diff --git a/swagger/sdrangel/api/swagger/include/DeviceReports.yaml b/swagger/sdrangel/api/swagger/include/DeviceReports.yaml index 45f3aa8fb..a72039419 100644 --- a/swagger/sdrangel/api/swagger/include/DeviceReports.yaml +++ b/swagger/sdrangel/api/swagger/include/DeviceReports.yaml @@ -71,7 +71,7 @@ DeviceReport: $ref: "http://swgserver:8081/api/swagger/include/Xtrx.yaml#/XtrxOutputReport" xtrxMIMOReport: $ref: "http://swgserver:8081/api/swagger/include/Xtrx.yaml#/XtrxMIMOReport" - aaroniaSDRReport: + AaroniaRTSAReport: $ref: "http://swgserver:8081/api/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSAReport" aaroniaRTSAOutputReport: $ref: "http://swgserver:8081/api/swagger/include/AaroniaRTSA.yaml#/AaroniaRTSAOutputReport" diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index d8f711d77..ad20c5244 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -2100,18 +2100,28 @@ margin-bottom: 20px; }; defs.AaroniaRTSAOutputReport = { "properties" : { - "centerFrequency" : { + "status" : { "type" : "integer", - "format" : "int64" - }, - "sampleRate" : { - "type" : "integer" + "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n" } }, "description" : "AaroniaRTSAOutput" }; defs.AaroniaRTSAOutputSettings = { "properties" : { + "centerFrequency" : { + "type" : "integer", + "format" : "int64", + "description" : "Sets the center frequency (Hz) of the distant IQ demodulator" + }, + "sampleRate" : { + "type" : "integer", + "description" : "Sets the sample rate (S/s) and span (Hz) of the distant IQ demodulator" + }, + "serverAddress" : { + "type" : "string", + "description" : "Distant AaroniaRTSA instance URL or IPv4 address with port" + }, "useReverseAPI" : { "type" : "integer", "description" : "Synchronize with reverse API (1 for yes, 0 for no)" @@ -2132,7 +2142,7 @@ margin-bottom: 20px; "properties" : { "status" : { "type" : "integer", - "description" : "0 for Idle, 1 for Connecting, 2 for Connected, 3 for Error, 4 for Disconnected" + "description" : "Connection to RTSA server status:\n * 0 - Idle\n * 1 - Unstable\n * 2 - Connected\n * 3 - Error\n * 4 - Disconnected\n" } }, "description" : "AaroniaRTSA" @@ -5276,7 +5286,7 @@ margin-bottom: 20px; "xtrxMIMOReport" : { "$ref" : "#/definitions/XtrxMIMOReport" }, - "aaroniaSDRReport" : { + "AaroniaRTSAReport" : { "$ref" : "#/definitions/AaroniaRTSAReport" }, "aaroniaRTSAOutputReport" : { @@ -57561,7 +57571,7 @@ except ApiException as e:
- Generated 2023-04-10T20:01:50.318+02:00 + Generated 2023-04-22T13:14:49.587+02:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.cpp b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.cpp index 2ee017b3f..ec5bfe0bd 100644 --- a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.cpp @@ -28,10 +28,8 @@ SWGAaroniaRTSAOutputReport::SWGAaroniaRTSAOutputReport(QString* json) { } SWGAaroniaRTSAOutputReport::SWGAaroniaRTSAOutputReport() { - center_frequency = 0L; - m_center_frequency_isSet = false; - sample_rate = 0; - m_sample_rate_isSet = false; + status = 0; + m_status_isSet = false; } SWGAaroniaRTSAOutputReport::~SWGAaroniaRTSAOutputReport() { @@ -40,16 +38,13 @@ SWGAaroniaRTSAOutputReport::~SWGAaroniaRTSAOutputReport() { void SWGAaroniaRTSAOutputReport::init() { - center_frequency = 0L; - m_center_frequency_isSet = false; - sample_rate = 0; - m_sample_rate_isSet = false; + status = 0; + m_status_isSet = false; } void SWGAaroniaRTSAOutputReport::cleanup() { - } SWGAaroniaRTSAOutputReport* @@ -63,9 +58,7 @@ SWGAaroniaRTSAOutputReport::fromJson(QString &json) { void SWGAaroniaRTSAOutputReport::fromJsonObject(QJsonObject &pJson) { - ::SWGSDRangel::setValue(¢er_frequency, pJson["centerFrequency"], "qint64", ""); - - ::SWGSDRangel::setValue(&sample_rate, pJson["sampleRate"], "qint32", ""); + ::SWGSDRangel::setValue(&status, pJson["status"], "qint32", ""); } @@ -83,34 +76,21 @@ SWGAaroniaRTSAOutputReport::asJson () QJsonObject* SWGAaroniaRTSAOutputReport::asJsonObject() { QJsonObject* obj = new QJsonObject(); - if(m_center_frequency_isSet){ - obj->insert("centerFrequency", QJsonValue(center_frequency)); - } - if(m_sample_rate_isSet){ - obj->insert("sampleRate", QJsonValue(sample_rate)); + if(m_status_isSet){ + obj->insert("status", QJsonValue(status)); } return obj; } -qint64 -SWGAaroniaRTSAOutputReport::getCenterFrequency() { - return center_frequency; -} -void -SWGAaroniaRTSAOutputReport::setCenterFrequency(qint64 center_frequency) { - this->center_frequency = center_frequency; - this->m_center_frequency_isSet = true; -} - qint32 -SWGAaroniaRTSAOutputReport::getSampleRate() { - return sample_rate; +SWGAaroniaRTSAOutputReport::getStatus() { + return status; } void -SWGAaroniaRTSAOutputReport::setSampleRate(qint32 sample_rate) { - this->sample_rate = sample_rate; - this->m_sample_rate_isSet = true; +SWGAaroniaRTSAOutputReport::setStatus(qint32 status) { + this->status = status; + this->m_status_isSet = true; } @@ -118,10 +98,7 @@ bool SWGAaroniaRTSAOutputReport::isSet(){ bool isObjectUpdated = false; do{ - if(m_center_frequency_isSet){ - isObjectUpdated = true; break; - } - if(m_sample_rate_isSet){ + if(m_status_isSet){ isObjectUpdated = true; break; } }while(false); diff --git a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.h b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.h index cb0e5c774..3c4597e03 100644 --- a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.h +++ b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputReport.h @@ -41,21 +41,15 @@ public: virtual void fromJsonObject(QJsonObject &json) override; virtual SWGAaroniaRTSAOutputReport* fromJson(QString &jsonString) override; - qint64 getCenterFrequency(); - void setCenterFrequency(qint64 center_frequency); - - qint32 getSampleRate(); - void setSampleRate(qint32 sample_rate); + qint32 getStatus(); + void setStatus(qint32 status); virtual bool isSet() override; private: - qint64 center_frequency; - bool m_center_frequency_isSet; - - qint32 sample_rate; - bool m_sample_rate_isSet; + qint32 status; + bool m_status_isSet; }; diff --git a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.cpp index 6eeee4f45..e775f3c02 100644 --- a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.cpp @@ -28,6 +28,12 @@ SWGAaroniaRTSAOutputSettings::SWGAaroniaRTSAOutputSettings(QString* json) { } SWGAaroniaRTSAOutputSettings::SWGAaroniaRTSAOutputSettings() { + center_frequency = 0L; + m_center_frequency_isSet = false; + sample_rate = 0; + m_sample_rate_isSet = false; + server_address = nullptr; + m_server_address_isSet = false; use_reverse_api = 0; m_use_reverse_api_isSet = false; reverse_api_address = nullptr; @@ -44,6 +50,12 @@ SWGAaroniaRTSAOutputSettings::~SWGAaroniaRTSAOutputSettings() { void SWGAaroniaRTSAOutputSettings::init() { + center_frequency = 0L; + m_center_frequency_isSet = false; + sample_rate = 0; + m_sample_rate_isSet = false; + server_address = new QString(""); + m_server_address_isSet = false; use_reverse_api = 0; m_use_reverse_api_isSet = false; reverse_api_address = new QString(""); @@ -57,6 +69,11 @@ SWGAaroniaRTSAOutputSettings::init() { void SWGAaroniaRTSAOutputSettings::cleanup() { + + if(server_address != nullptr) { + delete server_address; + } + if(reverse_api_address != nullptr) { delete reverse_api_address; } @@ -75,6 +92,12 @@ SWGAaroniaRTSAOutputSettings::fromJson(QString &json) { void SWGAaroniaRTSAOutputSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(¢er_frequency, pJson["centerFrequency"], "qint64", ""); + + ::SWGSDRangel::setValue(&sample_rate, pJson["sampleRate"], "qint32", ""); + + ::SWGSDRangel::setValue(&server_address, pJson["serverAddress"], "QString", "QString"); + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); @@ -99,6 +122,15 @@ SWGAaroniaRTSAOutputSettings::asJson () QJsonObject* SWGAaroniaRTSAOutputSettings::asJsonObject() { QJsonObject* obj = new QJsonObject(); + if(m_center_frequency_isSet){ + obj->insert("centerFrequency", QJsonValue(center_frequency)); + } + if(m_sample_rate_isSet){ + obj->insert("sampleRate", QJsonValue(sample_rate)); + } + if(server_address != nullptr && *server_address != QString("")){ + toJsonValue(QString("serverAddress"), server_address, obj, QString("QString")); + } if(m_use_reverse_api_isSet){ obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); } @@ -115,6 +147,36 @@ SWGAaroniaRTSAOutputSettings::asJsonObject() { return obj; } +qint64 +SWGAaroniaRTSAOutputSettings::getCenterFrequency() { + return center_frequency; +} +void +SWGAaroniaRTSAOutputSettings::setCenterFrequency(qint64 center_frequency) { + this->center_frequency = center_frequency; + this->m_center_frequency_isSet = true; +} + +qint32 +SWGAaroniaRTSAOutputSettings::getSampleRate() { + return sample_rate; +} +void +SWGAaroniaRTSAOutputSettings::setSampleRate(qint32 sample_rate) { + this->sample_rate = sample_rate; + this->m_sample_rate_isSet = true; +} + +QString* +SWGAaroniaRTSAOutputSettings::getServerAddress() { + return server_address; +} +void +SWGAaroniaRTSAOutputSettings::setServerAddress(QString* server_address) { + this->server_address = server_address; + this->m_server_address_isSet = true; +} + qint32 SWGAaroniaRTSAOutputSettings::getUseReverseApi() { return use_reverse_api; @@ -160,6 +222,15 @@ bool SWGAaroniaRTSAOutputSettings::isSet(){ bool isObjectUpdated = false; do{ + if(m_center_frequency_isSet){ + isObjectUpdated = true; break; + } + if(m_sample_rate_isSet){ + isObjectUpdated = true; break; + } + if(server_address && *server_address != QString("")){ + isObjectUpdated = true; break; + } if(m_use_reverse_api_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.h b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.h index eb4341f1d..567c1fff3 100644 --- a/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGAaroniaRTSAOutputSettings.h @@ -42,6 +42,15 @@ public: virtual void fromJsonObject(QJsonObject &json) override; virtual SWGAaroniaRTSAOutputSettings* fromJson(QString &jsonString) override; + qint64 getCenterFrequency(); + void setCenterFrequency(qint64 center_frequency); + + qint32 getSampleRate(); + void setSampleRate(qint32 sample_rate); + + QString* getServerAddress(); + void setServerAddress(QString* server_address); + qint32 getUseReverseApi(); void setUseReverseApi(qint32 use_reverse_api); @@ -58,6 +67,15 @@ public: virtual bool isSet() override; private: + qint64 center_frequency; + bool m_center_frequency_isSet; + + qint32 sample_rate; + bool m_sample_rate_isSet; + + QString* server_address; + bool m_server_address_isSet; + qint32 use_reverse_api; bool m_use_reverse_api_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGDeviceReport.cpp b/swagger/sdrangel/code/qt5/client/SWGDeviceReport.cpp index 56e5b6a7b..185096c5f 100644 --- a/swagger/sdrangel/code/qt5/client/SWGDeviceReport.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGDeviceReport.cpp @@ -92,8 +92,8 @@ SWGDeviceReport::SWGDeviceReport() { m_xtrx_output_report_isSet = false; xtrx_mimo_report = nullptr; m_xtrx_mimo_report_isSet = false; - aaronia_sdr_report = nullptr; - m_aaronia_sdr_report_isSet = false; + aaronia_rtsa_report = nullptr; + m_aaronia_rtsa_report_isSet = false; aaronia_rtsa_output_report = nullptr; m_aaronia_rtsa_output_report_isSet = false; } @@ -168,8 +168,8 @@ SWGDeviceReport::init() { m_xtrx_output_report_isSet = false; xtrx_mimo_report = new SWGXtrxMIMOReport(); m_xtrx_mimo_report_isSet = false; - aaronia_sdr_report = new SWGAaroniaRTSAReport(); - m_aaronia_sdr_report_isSet = false; + aaronia_rtsa_report = new SWGAaroniaRTSAReport(); + m_aaronia_rtsa_report_isSet = false; aaronia_rtsa_output_report = new SWGAaroniaRTSAOutputReport(); m_aaronia_rtsa_output_report_isSet = false; } @@ -270,8 +270,8 @@ SWGDeviceReport::cleanup() { if(xtrx_mimo_report != nullptr) { delete xtrx_mimo_report; } - if(aaronia_sdr_report != nullptr) { - delete aaronia_sdr_report; + if(aaronia_rtsa_report != nullptr) { + delete aaronia_rtsa_report; } if(aaronia_rtsa_output_report != nullptr) { delete aaronia_rtsa_output_report; @@ -353,7 +353,7 @@ SWGDeviceReport::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&xtrx_mimo_report, pJson["xtrxMIMOReport"], "SWGXtrxMIMOReport", "SWGXtrxMIMOReport"); - ::SWGSDRangel::setValue(&aaronia_sdr_report, pJson["aaroniaSDRReport"], "SWGAaroniaRTSAReport", "SWGAaroniaRTSAReport"); + ::SWGSDRangel::setValue(&aaronia_rtsa_report, pJson["AaroniaRTSAReport"], "SWGAaroniaRTSAReport", "SWGAaroniaRTSAReport"); ::SWGSDRangel::setValue(&aaronia_rtsa_output_report, pJson["aaroniaRTSAOutputReport"], "SWGAaroniaRTSAOutputReport", "SWGAaroniaRTSAOutputReport"); @@ -469,8 +469,8 @@ SWGDeviceReport::asJsonObject() { if((xtrx_mimo_report != nullptr) && (xtrx_mimo_report->isSet())){ toJsonValue(QString("xtrxMIMOReport"), xtrx_mimo_report, obj, QString("SWGXtrxMIMOReport")); } - if((aaronia_sdr_report != nullptr) && (aaronia_sdr_report->isSet())){ - toJsonValue(QString("aaroniaSDRReport"), aaronia_sdr_report, obj, QString("SWGAaroniaRTSAReport")); + if((aaronia_rtsa_report != nullptr) && (aaronia_rtsa_report->isSet())){ + toJsonValue(QString("AaroniaRTSAReport"), aaronia_rtsa_report, obj, QString("SWGAaroniaRTSAReport")); } if((aaronia_rtsa_output_report != nullptr) && (aaronia_rtsa_output_report->isSet())){ toJsonValue(QString("aaroniaRTSAOutputReport"), aaronia_rtsa_output_report, obj, QString("SWGAaroniaRTSAOutputReport")); @@ -800,13 +800,13 @@ SWGDeviceReport::setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report) { } SWGAaroniaRTSAReport* -SWGDeviceReport::getAaroniaSdrReport() { - return aaronia_sdr_report; +SWGDeviceReport::getAaroniaRtsaReport() { + return aaronia_rtsa_report; } void -SWGDeviceReport::setAaroniaSdrReport(SWGAaroniaRTSAReport* aaronia_sdr_report) { - this->aaronia_sdr_report = aaronia_sdr_report; - this->m_aaronia_sdr_report_isSet = true; +SWGDeviceReport::setAaroniaRtsaReport(SWGAaroniaRTSAReport* aaronia_rtsa_report) { + this->aaronia_rtsa_report = aaronia_rtsa_report; + this->m_aaronia_rtsa_report_isSet = true; } SWGAaroniaRTSAOutputReport* @@ -920,7 +920,7 @@ SWGDeviceReport::isSet(){ if(xtrx_mimo_report && xtrx_mimo_report->isSet()){ isObjectUpdated = true; break; } - if(aaronia_sdr_report && aaronia_sdr_report->isSet()){ + if(aaronia_rtsa_report && aaronia_rtsa_report->isSet()){ isObjectUpdated = true; break; } if(aaronia_rtsa_output_report && aaronia_rtsa_output_report->isSet()){ diff --git a/swagger/sdrangel/code/qt5/client/SWGDeviceReport.h b/swagger/sdrangel/code/qt5/client/SWGDeviceReport.h index a90a89712..03308bfee 100644 --- a/swagger/sdrangel/code/qt5/client/SWGDeviceReport.h +++ b/swagger/sdrangel/code/qt5/client/SWGDeviceReport.h @@ -169,8 +169,8 @@ public: SWGXtrxMIMOReport* getXtrxMimoReport(); void setXtrxMimoReport(SWGXtrxMIMOReport* xtrx_mimo_report); - SWGAaroniaRTSAReport* getAaroniaSdrReport(); - void setAaroniaSdrReport(SWGAaroniaRTSAReport* aaronia_sdr_report); + SWGAaroniaRTSAReport* getAaroniaRtsaReport(); + void setAaroniaRtsaReport(SWGAaroniaRTSAReport* aaronia_rtsa_report); SWGAaroniaRTSAOutputReport* getAaroniaRtsaOutputReport(); void setAaroniaRtsaOutputReport(SWGAaroniaRTSAOutputReport* aaronia_rtsa_output_report); @@ -275,8 +275,8 @@ private: SWGXtrxMIMOReport* xtrx_mimo_report; bool m_xtrx_mimo_report_isSet; - SWGAaroniaRTSAReport* aaronia_sdr_report; - bool m_aaronia_sdr_report_isSet; + SWGAaroniaRTSAReport* aaronia_rtsa_report; + bool m_aaronia_rtsa_report_isSet; SWGAaroniaRTSAOutputReport* aaronia_rtsa_output_report; bool m_aaronia_rtsa_output_report_isSet;