From 235de4fba34fd34927d216bca951fb6c566ac06d Mon Sep 17 00:00:00 2001 From: Christophe De Wagter Date: Fri, 7 Oct 2016 11:15:54 +0200 Subject: [PATCH] [payload] Payload Forward over UDP. --- .../TUDELFT/tudelft_control_panel.xml | 1 + conf/control_panel_example.xml | 1 + .../python/payload_forward/README.md | 13 ++ .../python/payload_forward/camera.ico | Bin 0 -> 125662 bytes .../python/payload_forward/jpeg100_decoder.py | 70 +++++++++ .../python/payload_forward/payload.py | 46 ++++++ .../python/payload_forward/payload_forward.py | 135 ++++++++++++++++++ 7 files changed, 266 insertions(+) create mode 100644 sw/ground_segment/python/payload_forward/README.md create mode 100755 sw/ground_segment/python/payload_forward/camera.ico create mode 100644 sw/ground_segment/python/payload_forward/jpeg100_decoder.py create mode 100755 sw/ground_segment/python/payload_forward/payload.py create mode 100644 sw/ground_segment/python/payload_forward/payload_forward.py diff --git a/conf/airframes/TUDELFT/tudelft_control_panel.xml b/conf/airframes/TUDELFT/tudelft_control_panel.xml index 96adec82648..a134a03c4d2 100644 --- a/conf/airframes/TUDELFT/tudelft_control_panel.xml +++ b/conf/airframes/TUDELFT/tudelft_control_panel.xml @@ -60,6 +60,7 @@ +
diff --git a/conf/control_panel_example.xml b/conf/control_panel_example.xml index 4eef094152d..5b668e57f21 100644 --- a/conf/control_panel_example.xml +++ b/conf/control_panel_example.xml @@ -66,6 +66,7 @@ +
diff --git a/sw/ground_segment/python/payload_forward/README.md b/sw/ground_segment/python/payload_forward/README.md new file mode 100644 index 00000000000..3f1cbbfcc4d --- /dev/null +++ b/sw/ground_segment/python/payload_forward/README.md @@ -0,0 +1,13 @@ +PAYLOAD +======= + +PAYLOAD (downlink) and PAYLOAD_COMMAND (uplink) messages in the pprzlink telemetry act as easy pass-through of information from an autopilot subsystem like a computer vision board to ground station payload control system. + +The paparazzi autopilot does not need to understand the data, but just needs to relay it. Payload is typically highly compressed information and only piggy-backs on telemetry when it needs to be transferred over the same long-range low bitrate datalink as the autopilot telemetry. + +The PAYLOAD sender (typically a paparazzi module) must make sure the telemetry datalink does not get flooded with payload. + + +Over the years some standards have developed for payload. One is sending jpeg-thumbnails-chunks. A decoder for this 'jpeg100' is added to the forwarding program. + +use ```payload.py --help``` to find currently supported options. diff --git a/sw/ground_segment/python/payload_forward/camera.ico b/sw/ground_segment/python/payload_forward/camera.ico new file mode 100755 index 0000000000000000000000000000000000000000..c4050acb85d2111dd0fe2dc10d5a1741dd187543 GIT binary patch literal 125662 zcmeI52e8$|9>y>Bu2>KiyC8~+ii#pO6s%)mEFc!_b-)?LijE`Bh&m`(5g7$5qoQI( z1w|}iMX_P;?V{LwdGGh$88g>xlABF7ImyX)95vay+1-5mWy`;9Q&SuMnK`qG|F&(4pooRdyEX|R4JL14&` zAtOeNc<7;rKKtymKmYvGDJhZ{_V?d^zxCEzLx&DsZ@u;ApMU;;P8-nw%ZI=UE37bJ zzpXU?3YOtE|Jl~-O_dF7QG5JbIF5CVJcwbxHS{bWZG``qjldi3ZK zRKL<169M-4H{N)oJyYzSxZ;W{8WTRfRX74jkbd~#2RowJ<+&OCuw&;)*N&@y8!FWQm*i ztFON5)TvV=W2biuM_{3a7MeYKc3iI5QM|tY{`((&^wGy3f6T?3Z@&4`OD|2GI(6*Wv8SAJ${u^{vHI$(r>U_l z&x%*JJ;i2clT9|kd>T_p#3{f1_FMdc9H|a!h!>LiT#Cr~$tRy&c;ST`Zn$CN&6VO+tGt3y-Me>Zi-$#%n@t=PA z{Oi*-w`|Y=hX%q9oUw{2|^5n@(j`PhoUv!g7@mKLGteciv zYAGhE@4ovkCNZ33!zd2>B{q^_ttv~pcxCn!6JMV`eO`O*HCw7+$^Y}uKSM>vH-21j zo4^g~i!Z*wg{sukqIl)w)#8gU&Sve$AAgKPDi-ixe)%QBI>gI(*J6dc_10T&w9!U* z9`R!i-D<0?cH3>Yk}tlwd57@%)9QoE6#Qg zk2yqAef#!ZYpu0n4lG!sAuMGi95rebVy;$eA;XLrGd9>@gO)8U%e8pr_0;<7ua96e zy1N-|aFk<`LXe(#fsI<0#oI2s?7~95)mai*#5UV(<2AA@7vfc|r;sE>JMI4d`|nex zOzG9DS7JH^QexwcH@@w*+oF9~h-I<&-g~>PH?T1d6U8gQM1KDH=buL`dys`@w~%Ij z?A^OJi?oOaunS<$Es?jlc!mGSJMX*`)~5_pS6+D~>mrBWa$r#?tj|9C?1=rs*I$3V zL=Gf-rv+kX4)-+S-9u=Wrdh_9f4EHax^WnL|@ z#1icO!a5OCgsxq?nuukcf_wP%>C?kn#m)jFimcm^zWmDainYqQ=bjt3`(uM&N9RXe z18~6$YugPs+_13R{J+ zS0*@f0qr*7`B`V36*#&wOBS%fHTs2tY<|vGDTVdNL5&+2MF*)-4#H2XPu|OnG7(#P z6Mt+Tu%Pg=73!i=yyDx(amMT*w8@7adT62g#n%|@NCQ8IM;>{km@p7mQJQBN)C*JhiyD2UOo~Q;kHt|I^l#9%)yGKOUl`V zVX$-O&baCzC&zM+Wj59?6pMTe&C9dTK8vAXw{G21Zr`wc2wcDu6ftGVS@5tryrTDs z8e#GZdn#;16JxvTs;lCvgC;R>Y3)@9C2+cd8#E(XT|9_v!7I?azz25erI$`tW_C|i zhgX3scF1u2@y92F7kxCwGng58UEJyg)7I&ypPqO{#40P0y}R$ed$L!^?y2hV>ckUI zG&=>et7L*}R!!%fcOD|IR=MQMKpPNfBpYEcc*YXUS0J|qj1OELUIhkIC6Ohu?PtrB zgdct4P={`~*)49i z*=8{-^|EmcjcNGD0Eqpem!}9972(zX`|oddJ=2G+aETG-l1nZzM+~#@I4St!*bZ43 z!{2w`eP-dw*g|Fy95Io|vzY zPqvEiYTUSSW?v9~!4_l;>Rb(0wf07}-9IOLE+%y&U$U|UY6`K!Py<_^vyHv8h3 zV~(-HmYw6oi4)Co(xeatBBr~v*HolfrZ+3*h>I?|sF$bi7ggXDJ9<;n&alI_&I*5A zv0i`u^)xIppT&}}W5YzXU^wW0j+F6y8Y33^MD$wefJ=6|6>|lj0J3(BJ zO>U$~L9)8-w%b}YgF|m&qpwoJj}%JOPz7Eg+$k7Dgxe1NAs4+H4Cif*uDofypcBacsNNN&W*4IKb=+!d}^$ZlWe0F=B+PA&Vn* zY)#Xd(;s-?0rOojGIRozt3s+EX8@}}I~n3&6T8?JN#Y1aM~pN(Jun4}cUomzJ3{pj zKKQ^_Ai@gS$=D+4B!8G)pRJ0p))@SEtd3jq(STdzt3!qiu{DyR_AtA?WY*M9unjDv zBI6Z3=++MT%rnnSEF)!jx%S#?6Kvmji$Eh8OkopHG>{Lj5-Y+h;0pAcK&^&aBmtNh zA>c5GRMQ-bqElF#U3Jw}gbGYnX<&F6BA_NHEz?J;!z;qG2Rb`*DrGW+F`HpK5FJR_ z$1xhf^k*xu@|s87+Q2OXq2Rqd1-YmWub3$UV_6em4Mk7l?jYJH<4<#Qb6}5qyuuLT z)?05)6LmIhDrXZxV35S^&*;JG@CpDCuzMZtUBCxhg^sT;=y4`f#yune@4ovk?ij4< zS$&~xVeiJVI75dH#X-YXq~NOs^-Z83{biS3R*cH<09;3Vqgw@D}eEpc< zmYI>^3%xKb;z!U10`A$Gg9g@1$$@b{aO&A|%Pj*Rsc&MXc*S?k64#@Xcfkhju)_|k zZ%0Jej!w|jHPe3Vt8HD1qAPOs*GlmU&{(|(9#zRIWwq5-bA_tga5YmKXT87x3F>j17we`RJpM7O=rJW>$??yfs4>Vyl*ns$H|# zKH`WYinazuz;1eK(_kd_w)Xk1#-cdoRFGFNho~KaVgZ5I0)!Vz!HHP_4(^O%LBVt)Mb#{(Nl7{Ee#-dBTCc;hxX1-?kTD1Av_okKQ75&0_e}S_hLj*xV5kvW~%Iy|8 z8#aewZ7XJ+c^^2HyRw;}kM#TO1-ydxs zh*WLQJ@+gTsdzi_%KOUL0CGk^#GnDk`0F#zJVUfw7G{aXk}!lYq5JN;FLpJkyglj$ zUJ&-*Ha>~>Ms>UpuUdjnBqC0Q2<%^9BJ(B^Z$jsx6^iLB#`>R-9ew-u9Xoa`W?In% zu2sk6$Z-ZOTNv{iKO>@Cn!nt3xZ;(sr?5Q77cWd?>SGtTOj1~!-g3(=81Ef;;DMYq zi6#gKE`H3dy?XV+0}I<@gierzI54daP_-(UcJZxf-@d)Cc`$A8 zeFzd%zs4#^^h?SD@$9#&B4G%}GVi+yczm#~D9>c6lKy1Zg z38$Mt+jx^9wkgb*MD0N4>Ci||yvmvtuF6NMfN9EUr=5m@4P%QfdCdH*%uzuiWADSwFM6^iLM<)o$mT<<58N^M(kH*QA7x>~7j*h_m!MDKt z&J#1*4+34ee$i!w90|F=6FH5z zpe}EbzEVD%n{U3^36Xq-VC(^~>0780%7_5p7mEZRC7j$M5=?MXRT(iG{hqu@UB#ZJ?1>_t19dV;`NF-lT=*9Z=>(|%->g`Mf@EX8c z!$$_Ux7ZHhuVhxOlmGgIR3AJVbrU&L;!2CXp3%J{)FY{#Ens- zM#Z#zYuQ3wmkt5urs>nChcUrpn$OoOV@ElZgAVSZ3)I@Yq6G|Y_n(2?%A_v zb{erFW8Tn>Q~RB^*9Q z@Kqe9h^vn&IN>#zADvr?6udji+dPPbEFJAR zpvDuSYC1|5s{|@3<0O>><(%+}b^HY^7%e8@L=3Avgnb7%(94Op3;!gp;>G_(0Hum_M8pTCEfx zy@L-vxPcuOdiU;~vuk#%m{%kNQWv5u=D$13p+=mt15Y}rNYB>&HBmR@7N{o&I@PM^ z*s&vW;JRa5@djYZ*tKid+&Vq$ia0BZ@JAKz(}KJ{ns>hOtb06%@(KFK(MttERm}ha zPLv>!V-8)PT@}cCCr_R%`DfAij7>#(ZSV1_#+IOHkg7d31g1=xQbq+L0pD)A=_U!) z3rk}rk5tF{B2{5YRcjd3A_z=b)>@G2&O7fEsR~XiuX#ihD*g_Upra2z{IJ(% zU6cX=77yZMGHB2sscC$j zRjyl>E*LO#HXM5{>>ui-r>0(vURX_W))J8qwV)~&iy~S(ckW!gEXR)@Ke`^japT5u z7!!v$N3>9X5&}X%2nYcoAOwVf5D)@FKnMr{As_^VfDjM@LO=)z0U;m+gn$qb0zyCt z2mv7=1cZPP5CTF#2nYcoAOwVf5D)@FKnMr{As_^VfDjM@LO=)z0U;m+gn$qb0zyCt z2mv7=1cZPP5CTF#2nYcoAOwU!MG(j$B%R6>0zyCt2mv7=1cZPP5CTF#2nYcoAOwVf P5D)@FKnMtd>=F1cDffF> literal 0 HcmV?d00001 diff --git a/sw/ground_segment/python/payload_forward/jpeg100_decoder.py b/sw/ground_segment/python/payload_forward/jpeg100_decoder.py new file mode 100644 index 00000000000..d1cb3c6f84a --- /dev/null +++ b/sw/ground_segment/python/payload_forward/jpeg100_decoder.py @@ -0,0 +1,70 @@ +# +# Copyright (C) 2016 TUDelft +# +# This file is part of paparazzi. +# +# paparazzi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# paparazzi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with paparazzi. If not, see . +# + +import wx +import array +import Image +from cStringIO import StringIO + + +jpegheader = b'\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x20\x16\x18\x1c\x18\x14\x20\x1c\x1a\x1c\x24\x22\x20\x26\x30\x50\x34\x30\x2c\x2c\x30\x62\x46\x4a\x3a\x50\x74\x66\x7a\x78\x72\x66\x70\x6e\x80\x90\xb8\x9c\x80\x88\xae\x8a\x6e\x70\xa0\xda\xa2\xae\xbe\xc4\xce\xd0\xce\x7c\x9a\xe2\xf2\xe0\xc8\xf0\xb8\xca\xce\xc6\xff\xdb\x00\x43\x01\x22\x24\x24\x30\x2a\x30\x5e\x34\x34\x5e\xc6\x84\x70\x84\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xc6\xff\xc0\x00\x11\x08\x00\x64\x00\x64\x03\x01\x22\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x41\x06\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02\x77\x00\x01\x02\x03\x11\x04\x05\x21\x31\x06\x12\x41\x51\x07\x61\x71\x13\x22\x32\x81\x08\x14\x42\x91\xa1\xb1\xc1\x09\x23\x33\x52\xf0\x15\x62\x72\xd1\x0a\x16\x24\x34\xe1\x25\xf1\x17\x18\x19\x1a\x26\x27\x28\x29\x2a\x35\x36\x37\x38\x39\x3a\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79\x7a\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00\x3f\x00' + +class ThumbNailFromPayload: + + def add_payload(self, lst): + + if lst[1] == 255: + self.thumb = self.pay + elif lst[1] == 0: + self.pay = lst[3:] + else: + self.pay.extend(lst[3:]) + + + def __init__(self): + + self.pay = [] + self.thumb = [] + self.last_good_bitmap = None + + def get_image(self): + + self.jpgdata = jpegheader + bytearray(self.thumb) + file_jpgdata = StringIO(self.jpgdata) + img = Image.open(file_jpgdata) + return img + + def get_bitmap(self): + + myPilImage = self.get_image() + myWxImage = wx.EmptyImage( myPilImage.size[0], myPilImage.size[1] ) + myWxImage.SetData( myPilImage.convert( 'RGB' ).tostring() ) + bitmap = wx.BitmapFromImage(myWxImage) + return bitmap + + def draw(self, dc, x, y): + # Jpeg: might be corrupt/incomplete + try: + bitmap = self.get_bitmap() + dc.DrawBitmap(bitmap, x,y, True) + self.last_good_bitmap = bitmap + except IOError: + if self.last_good_bitmap is not None: + dc.DrawBitmap(self.last_good_bitmap, x,y, True) + diff --git a/sw/ground_segment/python/payload_forward/payload.py b/sw/ground_segment/python/payload_forward/payload.py new file mode 100755 index 00000000000..d88b4c33f67 --- /dev/null +++ b/sw/ground_segment/python/payload_forward/payload.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# Copyright (C) 2016 TUDelft +# +# This file is part of paparazzi. +# +# paparazzi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# paparazzi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with paparazzi. If not, see . +# + +import wx +import sys +import argparse +import payload_forward + +parser = argparse.ArgumentParser(description='Capture PAYLOAD messages over the IVY bus and forward to a remote application.', epilog='payload.py is part of the paparazzi-uav project.') +parser.add_argument('--ip', '-i', default="192.168.0.1", help='Destination IP ADDRESS (default=192.168.0.1)') +parser.add_argument('--port','-p', type=int, default=32000, help='Destination PORT (default=32000)') +parser.add_argument('--decoder','-d', default='jpeg100', help='Payload decoder. (default=jpeg100)', choices=['none', 'jpeg100']) +settings = parser.parse_args() + +print(settings) + +class PayloadFrame(wx.App): + def OnInit(self): + self.main = payload_forward.PayloadForwarderFrame(settings) + self.main.Show() + self.SetTopWindow(self.main) + return True + +def main(): + application = PayloadFrame(0) + application.MainLoop() + +if __name__ == '__main__': + main() diff --git a/sw/ground_segment/python/payload_forward/payload_forward.py b/sw/ground_segment/python/payload_forward/payload_forward.py new file mode 100644 index 00000000000..6ef266c3a1c --- /dev/null +++ b/sw/ground_segment/python/payload_forward/payload_forward.py @@ -0,0 +1,135 @@ +# +# Copyright (C) 2016 TUDelft +# +# This file is part of paparazzi. +# +# paparazzi is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# paparazzi is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with paparazzi. If not, see . +# + +import wx +import sys +import os +import threading +import socket +import array +import jpeg100_decoder +from cStringIO import StringIO + + +PPRZ_SRC = os.getenv("PAPARAZZI_SRC", os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../../..'))) + +sys.path.append(PPRZ_SRC + "/sw/ext/pprzlink/lib/v1.0/python") + +from pprzlink.ivy import IvyMessagesInterface + +WIDTH = 300 + + +# Minimal Decoder +class MinimalDecoder: + def __init__(self): + self.data = [] + def add_payload(self,bytes): + self.data = bytes + + def draw(self,dc,x,y): + dc.DrawText( "Payload: " + str(self.data),x,y) + + +class PayloadForwarderFrame(wx.Frame): + + def message_recv(self, ac_id, msg): + if msg.name == "PAYLOAD": + # convert text to binary + pld = msg.get_field(0).split(",") + b = [] + for p in pld: + b.append(int(p)) + + # forward over UDP + self.data['packets'] = self.data['packets'] + 1 + self.data['bytes'] = self.data['bytes'] + len(b) + self.sock.sendto(bytearray(b), (self.settings.ip, self.settings.port)) + + # send to decoder + self.decoder.add_payload(b) + + # graphical update + wx.CallAfter(self.update) + + def update(self): + self.Refresh() + + def OnSize(self, event): + self.w = event.GetSize()[0] + self.h = event.GetSize()[1] + self.Refresh() + + def OnPaint(self, e): + # Paint Area + dc = wx.PaintDC(self) + brush = wx.Brush("white") + dc.SetBackground(brush) + dc.Clear() + + # Background + dc.SetBrush(wx.Brush(wx.Colour(0,0,0), wx.TRANSPARENT)) + font = wx.Font(11, wx.ROMAN, wx.BOLD, wx.NORMAL) + dc.SetFont(font) + dc.DrawText("UDP: " + self.settings.ip + ":" + str(self.settings.port),2,2) + dc.DrawText("Data: " + str(self.data['packets']) + " packets, " + str(round(float(self.data['bytes'])/1024.0,2)) + "kb)",2,22) + dc.DrawText("Decoder: " + self.settings.decoder ,2,42) + + # Payload visual representation + self.decoder.draw(dc, 2, 62) + + + def __init__(self, _settings): + + # Command line arguments + self.settings = _settings + + # Statistics + self.data = { 'packets': 0, 'bytes': 0} + + # Decoder + if (self.settings.decoder is 'jpeg100'): + self.decoder = jpeg100_decoder.ThumbNailFromPayload() + else: + self.decoder = MinimalDecoder() + + self.w = WIDTH + self.h = WIDTH + + # Socket + self.sock = socket.socket(socket.AF_INET, # Internet +socket.SOCK_DGRAM) # UDP + + # Frame + wx.Frame.__init__(self, id=-1, parent=None, name=u'Payload Forwarding', + size=wx.Size(self.w, self.h), title=u'Payload Forwarding') + ico = wx.Icon(os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)))) + "/camera.ico", wx.BITMAP_TYPE_ICO) + self.SetIcon(ico) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_CLOSE, self.OnClose) + + # IVY + self.interface = IvyMessagesInterface("PayloadForwarder") + self.interface.subscribe(self.message_recv) + + def OnClose(self, event): + self.interface.shutdown() + self.Destroy()