def __init__(self):
        self.lasttime = time.clock()
        
        super(GroundStation, self).__init__(parent = None)
        self.SetIcon(wx.Icon(r'resources/gs.ico', wx.BITMAP_TYPE_ICO))              
        
        #---- init status bar system ----
        self.sbar = StatusBarSystem(self.m_statusBar)
        
        #---- add Google Earth Components ----  
        sizer_ge = self.m_panel_route.GetSizer()
        self.browser_ge = wx.html2.WebView.New(self.m_panel_route, size=(330,330))
        sizer_ge.Add(self.browser_ge, 1, wx.ALIGN_CENTER, 0)
        self.browser_ge.LoadURL(r'file:///%s/resources/ge.html'%os.getcwd().replace('\\','/'))
        self.GE_uninited = True
                
        #---- set record labels ----
        self.m_filePicker_output.GetPickerCtrl().SetLabel(u'设置视频参数')
        
        #---- add component attributes ----
        for comp in [self.m_button_toggle_track, 
                     self.m_button_toggle_track_video,
                     self.m_button_toggle_video,
                     self.m_button_toggle_xbee,
                     self.m_button_update_uavinfo,
                     self.m_button_select_object,
                     self.m_button_record,
                     self.m_button_toggle_joystick,
                     ]:
            comp.__setattr__('is_running', False)

        #---- init comm block ----
        self.comm = XBee(self)
        self.comm_options = {}
        self.load_default_comm_options()
        self.history = InputHistory(self)
        self.enable_comm_relative_components(False)
        
        #---- init video block ----
        self.cap_dev_num = 1
        self.enable_video_components(False)
        self.video_window = None
        
        #---- init track block ----
        self.enable_track_components(False)
        self.display_track_state = None
        
        #---- init parameter adjust block ----
        self.init_para_block()
        
        #---- init size variables ----
        self.bitmap_track_size = tuple(self.m_bitmap_track.GetSize())
        self.bitmap_video_size = tuple(self.m_bitmap_video.GetSize())
        
        #---- init UAVInformation ----
        self.UAVinfo = UAVInfomation()
        
        #---- init UAV Control ----
        self.init_uav_control()
        
        # --- dc init ---
        self.dc_video = wx.ClientDC(self.m_bitmap_video)
        self.dc_track = wx.ClientDC(self.m_bitmap_track)
        self.memory = wx.MemoryDC()
        self.dc_attitude = wx.ClientDC(self.m_bitmap_attitude)
        self.dc_uavinfo = wx.ClientDC(self.m_bitmap_uavinfo)
        
        # --- test ---
        self.multimean_arg = None
        self.edge_arg = None
        
        self.init_worklist()
        #self.Bind(wx.EVT_IDLE, self.main_work)
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.main_work, self.timer)
        self.timer.Start(1000.0/MAIN_TASK_FREQ)
        self.timer.last_time=time.clock()
        
#         self.timer1 = wx.Timer(self) 
#         self.Bind(wx.EVT_TIMER, self.main_work1, self.timer1)
#         self.timer1.Start(1000/10)
        
        self.Bind(wx.EVT_CLOSE, self.OnClose)
class GroundStation(FrameGroundStationBase, WorkBlock ,TrackBlock, VideoBlock,
                    ButtonBlock, MenuBlock, CommBlock, ParameterAdjustBlock,
                    UAVCtrlBlock
                    ):
    def __init__(self):
        self.lasttime = time.clock()
        
        super(GroundStation, self).__init__(parent = None)
        self.SetIcon(wx.Icon(r'resources/gs.ico', wx.BITMAP_TYPE_ICO))              
        
        #---- init status bar system ----
        self.sbar = StatusBarSystem(self.m_statusBar)
        
        #---- add Google Earth Components ----  
        sizer_ge = self.m_panel_route.GetSizer()
        self.browser_ge = wx.html2.WebView.New(self.m_panel_route, size=(330,330))
        sizer_ge.Add(self.browser_ge, 1, wx.ALIGN_CENTER, 0)
        self.browser_ge.LoadURL(r'file:///%s/resources/ge.html'%os.getcwd().replace('\\','/'))
        self.GE_uninited = True
                
        #---- set record labels ----
        self.m_filePicker_output.GetPickerCtrl().SetLabel(u'设置视频参数')
        
        #---- add component attributes ----
        for comp in [self.m_button_toggle_track, 
                     self.m_button_toggle_track_video,
                     self.m_button_toggle_video,
                     self.m_button_toggle_xbee,
                     self.m_button_update_uavinfo,
                     self.m_button_select_object,
                     self.m_button_record,
                     self.m_button_toggle_joystick,
                     ]:
            comp.__setattr__('is_running', False)

        #---- init comm block ----
        self.comm = XBee(self)
        self.comm_options = {}
        self.load_default_comm_options()
        self.history = InputHistory(self)
        self.enable_comm_relative_components(False)
        
        #---- init video block ----
        self.cap_dev_num = 1
        self.enable_video_components(False)
        self.video_window = None
        
        #---- init track block ----
        self.enable_track_components(False)
        self.display_track_state = None
        
        #---- init parameter adjust block ----
        self.init_para_block()
        
        #---- init size variables ----
        self.bitmap_track_size = tuple(self.m_bitmap_track.GetSize())
        self.bitmap_video_size = tuple(self.m_bitmap_video.GetSize())
        
        #---- init UAVInformation ----
        self.UAVinfo = UAVInfomation()
        
        #---- init UAV Control ----
        self.init_uav_control()
        
        # --- dc init ---
        self.dc_video = wx.ClientDC(self.m_bitmap_video)
        self.dc_track = wx.ClientDC(self.m_bitmap_track)
        self.memory = wx.MemoryDC()
        self.dc_attitude = wx.ClientDC(self.m_bitmap_attitude)
        self.dc_uavinfo = wx.ClientDC(self.m_bitmap_uavinfo)
        
        # --- test ---
        self.multimean_arg = None
        self.edge_arg = None
        
        self.init_worklist()
        #self.Bind(wx.EVT_IDLE, self.main_work)
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.main_work, self.timer)
        self.timer.Start(1000.0/MAIN_TASK_FREQ)
        self.timer.last_time=time.clock()
        
#         self.timer1 = wx.Timer(self) 
#         self.Bind(wx.EVT_TIMER, self.main_work1, self.timer1)
#         self.timer1.Start(1000/10)
        
        self.Bind(wx.EVT_CLOSE, self.OnClose)

        
#------ Menu binding function ------
    def on_about(self, event):
        self.about()
    
    def on_save_comm_option(self, event): 
        self.save_comm_option(self.comm_options)
    
    
    def on_load_comm_option(self, event):
        self.load_comm_option()
    
    def on_check_comm_option(self, event):
        self.load_default_comm_options()
        self.display_comm_option(self.comm_options)
    
 #------ Button binding function ------   
    
    def on_xbee_option(self, event):
        self.show_xbee_option()
    
    def on_toggle_xbee(self, event):        
        if event.GetEventObject().is_running:
            self.close_xbee(event.GetEventObject())
        else:
            self.open_xbee(event.GetEventObject())
    
    def on_toggle_video(self, event):
        if event.GetEventObject().is_running:
            self.close_video(event.GetEventObject())
        else:
            self.open_video(event.GetEventObject())
    
    def on_video_comm_option(self, event):
        self.show_video_option()
    
    def on_update_uavinfo(self, event):
        if event.GetEventObject().is_running:
            self.unshow_uavinfo(event.GetEventObject())
        else:
            self.show_uavinfo(event.GetEventObject())
    
    def on_save_uav_info(self, event):
        self.UAVinfo.save_to_file(self, pidpara = self.get_para_from_table())
        if self.m_menuItem_clear_uav_info_after_save.IsChecked():
            self.UAVinfo.clear_buf()
        self.update_GUI_UAVinfo(self.UAVinfo.get())
    
    def on_clear_uav_info(self, event):
        self.UAVinfo.clear_buf()
        self.update_GUI_UAVinfo(self.UAVinfo.get())

#------ Video Binding Function ------    
    def on_video_window_show(self, event):
        self.show_independent_video()
        
    def on_record(self, event):
        if event.GetEventObject().is_running:
            self.stop_record(event.GetEventObject())
        else:
            self.start_record(event.GetEventObject())
    
    def on_record_file_changed(self, event):
        self.init_record(self.m_filePicker_output.GetPath())
    
    def on_enter_bitmap_video(self, event):
        self.sbar.update(u'提示:单击右键可选择OSD选项')
    
    def on_leave_bitmap_video(self, event):
        self.sbar.backward()

#------ UAV Control Binding Function ------
    def on_PT_send(self, event):
        rtn = self.send_pt_reference()
        self.sbar.update(u'云台控制信息已经发送(%d)'%rtn)
    
    def on_toggle_joystick(self, event):
        if event.GetEventObject().is_running:
            self.close_joystick(event.GetEventObject())
        else:
            self.open_joystick(event.GetEventObject())
    
    def on_toggle_smart_direction(self, event):
        self.toggle_smart_direction(self.m_checkBox_smart_direction.IsChecked())
        
#------ Track Binding Function ------   

    def on_toggle_track_video(self, event):
        if event.GetEventObject().is_running:
            self.close_track_video(event.GetEventObject())
        else:
            self.open_track_video(event.GetEventObject())
     
    def on_radiobox_adjust(self, event):
        self.change_adjust_type()
     
    def on_slider_adjust_changed(self, event):
        self.change_adjust_value()
     
    def on_select_object(self, event):
        self.toggle_drag_selection(True)
         
    def on_toggle_track(self, event):
        if event.GetEventObject().is_running:
            self.stop_track(event.GetEventObject())
        else:
            self.start_track(event.GetEventObject())
    
    def on_track_bitmap_left_down(self, event):
        self.start_drag(event)
     
    def on_track_bitmap_left_up(self, event):
        self.end_drag(event)
     
    def on_track_bitmap_motion(self, event):
        self.on_drag(event)
    
    def on_track_arg_enter(self, event):
        self.set_track_arg(event.GetEventObject().GetValue())
    
    def on_enter_bitmap_track(self, event):
        self.sbar.update(u'提示:单击右键可选择显示模式和分辨模式')
    
    def on_leave_bitmap_track(self, event):
        self.sbar.backward()

#------ Parameter Adjust Binding Function ------
    def on_send_para(self, event):
        self.send_para((self.m_checkBox_para_x.IsChecked(),
                        self.m_checkBox_para_y.IsChecked(),
                        self.m_checkBox_para_z.IsChecked(),
                        self.m_checkBox_para_h.IsChecked(),
                        self.m_checkBox_para_p.IsChecked(),
                        )
                       )
    
    def on_load_para(self, event):
        self.load_para()
    
    def on_save_para(self, event):
        self.save_para()
    
    def on_set_down_para(self, event):
        self.set_down_para()

#------ Communication Binding Function ------   
    def on_send_area_enter(self, event):
        self.send_data_by_GUI()
    
    def on_send_comm_click(self, event):
        self.send_data_by_GUI()
    
    def on_send_area_char(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_UP:
            self.m_textCtrl_comm_send.SetValue(self.history.getByRel(-1))
            self.m_textCtrl_comm_send.SetInsertionPoint(len(self.m_textCtrl_comm_send.GetValue()))
        elif keycode == wx.WXK_DOWN:
            self.m_textCtrl_comm_send.SetValue(self.history.getByRel(1))
            self.m_textCtrl_comm_send.SetInsertionPoint(len(self.m_textCtrl_comm_send.GetValue()))
        else:
            FrameGroundStationBase.on_send_comm_char(self, event)
    
    def on_clear_receive(self, event):
        self.comm.clear_rcvbuf()
        self.update_rcv_area(refresh = True)
    
    def on_recv_style_choice(self, event):
        self.update_rcv_area(refresh = True)

        
#------ CallAfter Function ------
    def on_xbee_receive_char(self,rcvchr):
        self.comm.on_receive_char(rcvchr)
        msgtype, data = self.get_backdata()
        if data:
            self.process_backdata(msgtype, data)
     
    
#------ Work Function ------        
    def main_work(self, event):
        
        worklist = self.worklist
        a = time.clock()        
        
        # 5 Hz Tasks
        if (time.clock()-self.timer.last_time) > 1.0/5:
            self.timer.last_time=time.clock()
            
            if DISPLAY_XBEE_DATA in worklist:
                self.update_rcv_area()
            
            if USING_JOYSTICK in self.worklist:
                self.do_joy_control()
            
            # 发送MID=0x09时自动返回,不需重复发送。
            if DISPLAY_UAVINFO in self.worklist and USING_JOYSTICK not in self.worklist:
                self.send_data_by_frame(MsgPrcs.pack_control(0, self.state_smart_direction))
        
            if DISPLAY_UAVINFO in self.worklist:
                self.update_GUI_UAVinfo(self.UAVinfo.get())
        
        # MAIN_TASK_FREQ Hz Tasks
            
        
        if USING_JOYSTICK in self.worklist:
                self.update_joy_status()
        
        if DISPLAY_VIDEO in worklist:
            srcimg = self.camcap.get_frame()
            wxbmp = util.cvimg_to_wxbmp(srcimg)
            wximg = wx.ImageFromBitmap(wxbmp)
            memvideo = wx.MemoryDC()
            memvideo.SelectObject(wxbmp)

            if self.m_menuItem_video_osd.IsChecked():
                # draw OSD information on bitmap_video
                memvideo.SetTextForeground( wx.BLUE )
                memvideo.SetFont( util.WXFONT )
                pos = (srcimg.shape[1] - util.PADDING - util.TIME_TEXT_WIDTH, util.PADDING)
                memvideo.DrawText(util.get_now(), pos[0], pos[1])

            # 设置缩放比例
            memvideo.SetUserScale(float(srcimg.shape[1])/float(self.bitmap_video_size[0]),
                                float(srcimg.shape[0])/float(self.bitmap_video_size[1])
                                )
            self.dc_video.Blit(0, 0, self.bitmap_video_size[0], self.bitmap_video_size[1], memvideo, 0, 0)
            memvideo.SelectObject(wx.NullBitmap)
            
        
        if RECORD_VIDEO in worklist:
            self.mov_rec.save_frame(wxbmp)
            
        if DISPLAY_INDEPENDENT_VIDEO in worklist:
            self.video_window.update_image_with_info1(wximg, self.UAVinfo.get_information_in_InfoEntries())
        
       
        # 结束图像传输需要先停止track
        if DISPLAY_TRACK_VIDEO in worklist:       
            memtrack = wx.MemoryDC()
            # 显示原始图像
            if self.display_track_state == DISPLAY_TRACK_STATE_RAW:
                #rstimg = self.get_adjusted_image(srcimg)
                rstimg = srcimg
                rstbmp = util.cvimg_to_wxbmp(rstimg)           
            # 正在框选状态
            elif self.display_track_state == DISPLAY_TRACK_STATE_SELECTION:
                assert self.frozen_frame is not None, 'Frozen frame is none.'
                rectimg = self.get_dragging_image(self.frozen_frame,self.drag_info.get_drag_data())
                rstbmp = util.cvimg_to_wxbmp(rectimg)
            # 显示目标追踪结果
            elif self.display_track_state == DISPLAY_TRACK_STATE_RESULT:
                track_mode = self.m_choice_track_mode.GetStringSelection()
                display_process = self.m_menuItem_track_display_process.IsChecked()
                if track_mode == 'template':
                    method = METHOD.TEMPLATEMATCH
                elif track_mode == 'meanshift':
                    method = METHOD.MEANSHIFT
                elif track_mode == 'gray-meanshift':
                    method = METHOD.GRAYMEANSHIFT
                else:
                    method = METHOD.OPTICALFLOW
                
                matchimg, center, res = self.objmatch.process(method, srcimg)
                if display_process:
                    rstbmp = util.cvimg_to_wxbmp(res)
                else:
                    rstbmp = util.cvimg_to_wxbmp(matchimg)
            
                
#                 # 模板匹配模式
#                 if track_mode == 'template':
#                     matchimg, center, res = self.objmatch.do_tpl_match(srcimg)
#                     if display_process:
#                         rstbmp = util.cvimg_to_wxbmp(res)
#                     else:
#                         rstbmp = util.cvimg_to_wxbmp(matchimg)
#                 # 边缘检测-模板匹配模式
#                 elif track_mode == 'edge-tpl':
#                     matchimg, center, edgeimg = self.objmatch.do_edge_match(srcimg, arg=self.edge_arg)
#                     if display_process:
#                         rstbmp = util.cvimg_to_wxbmp(edgeimg)
#                     else:
#                         rstbmp = util.cvimg_to_wxbmp(matchimg)
#                 # MeanShift匹配模式
#                 elif track_mode == 'meanshift':
#                     matchimg, center, prj_img = self.objmatch.do_meanshift(srcimg)
#                     if display_process:
#                         rstbmp = util.cvimg_to_wxbmp(prj_img)
#                     else:
#                         rstbmp = util.cvimg_to_wxbmp(matchimg)
#                 # 多目标MeanShift匹配模式
#                 elif track_mode == 'multi-meanshift':
#                     matchimg, center, prj_img = self.objmatch.do_multi_meanshift(srcimg, arg=self.multimean_arg)
#                     if display_process:
#                         rstbmp = util.cvimg_to_wxbmp(prj_img)
#                     else:
#                         rstbmp = util.cvimg_to_wxbmp(matchimg)
#                 elif track_mode == 'gray-meanshift':
#                     matchimg, center, prj_img = self.objmatch.do_gray_meanshift(srcimg)
#                     if display_process:
#                         rstbmp = util.cvimg_to_wxbmp(prj_img)
#                     else:
#                         rstbmp = util.cvimg_to_wxbmp(matchimg)
#                 elif track_mode == 'optical-flow':
#                     matchimg, center, prj_img = self.objmatch.do_optical_flow(srcimg)
#                     if display_process:
#                         rstbmp = util.cvimg_to_wxbmp(prj_img)
#                     else:
#                         rstbmp = util.cvimg_to_wxbmp(matchimg)
#                 # 混合匹配模式
#                 elif track_mode == 'mix':
#                     matchimg, center, _ = self.objmatch.do_mix(srcimg, multimean_arg=self.multimean_arg, edgetpl_arg=self.edge_arg)    
#                     rstbmp = util.cvimg_to_wxbmp(matchimg)
            # 更新track bitmap 界面
            memtrack.SelectObject(rstbmp)
            memtrack.SetUserScale(float(srcimg.shape[1])/float(self.bitmap_track_size[0]),
                             float(srcimg.shape[0])/float(self.bitmap_track_size[1]))
            self.dc_track.Blit(0, 0, self.bitmap_track_size[0], self.bitmap_track_size[1], memtrack, 0, 0)
            a = time.clock()
                
        
        if TRACK_OBJECT in worklist:
            self.trackctrl.add_pt(center)
            self.trackctrl.update_h(self.UAVinfo.get()['height'])
            self.trackctrl.get_u()
            
            rstimg = self.objmatch.draw_circles(matchimg, self.trackctrl.pts[-1], color='GREEN', radius=10)
            rstbmp = util.cvimg_to_wxbmp(rstimg)
            memtrack.SelectObject(rstbmp)
            memtrack.SetUserScale(float(srcimg.shape[1])/float(self.bitmap_track_size[0]),
                             float(srcimg.shape[0])/float(self.bitmap_track_size[1]))
            self.dc_track.Blit(0, 0, self.bitmap_track_size[0], self.bitmap_track_size[1], memtrack, 0, 0)
        
        n = time.clock()
#         print('[work time]%4.4f [cir time]%4.4f'%((n-a)*1000,(n-self.lasttime)*1000))
        self.lasttime = n
    
#------ Tool Function ------       
    def update_GUI_UAVinfo(self, info):
        # update text info
        for k,v in info.iteritems():
            if v is None:
                info[k] = float('nan')

        mem = wx.MemoryDC()
        mem.SetFont(util.WXFONT)
        
        csz = mem.GetTextExtent(' ')
        sz = (45*csz[0], 9*csz[1])
        
        self.m_bitmap_uavinfo.SetSize(sz)
        self.m_bitmap_uavinfo.CenterOnParent()
        mem.SelectObject(wx.BitmapFromImage(wx.ImageFromData(sz[0],sz[1],'\xf0'*sz[0]*sz[1]*3)))
        
        pos = (0,5)
        padding = csz[0]*4
        
        def write(s, color):
            if color is None:
                color = wx.BLUE
            mem.SetTextForeground(color)
            mem.DrawText(s, pos[0], pos[1])
            return (pos[0] + mem.GetTextExtent(s)[0] + padding, pos[1])
        
        def writeln(s, color):
            rtn =  write(s, color)
            return (0, rtn[1]+csz[1])
            
        def get_st_color(value):
            if value == 0:
                return wx.Colour(255,0,0)
            elif value == 2:
                return wx.Colour(255,255,0)
            elif value == 1:
                return wx.Colour(20,215,0)
            else:
                return wx.Colour(160,160,160)
        
        pos = writeln('--UAVInfo Display--    UAVTime :%9.3Fs'%info['uavtime'], None)
        pos = writeln('', None)
        pos = writeln(' pitch  =%9.3Fd    Rpitch  =%9.3Fd'%(info['pitch'], info['ref_pitch']), None)
        pos = writeln(' roll   =%9.3Fd    Rroll   =%9.3Fd'%(info['roll'], info['ref_roll']), None)
        pos = writeln(' yaw    =%9.3Fd    Ryaw    =%9.3Fd'%(info['yaw'], info['ref_yaw']), None)
        pos = write(' height =%9.3Fm'%info['height'],
                    wx.RED if self.UAVinfo.need_warning('height', info['height']) else None)
        pos = writeln('Rheight =%9.3Fm\n'%(info['ref_height']), None)
        pos = write(' volt   =%9.3FV'%info['volt'],
                    wx.RED if self.UAVinfo.need_warning('volt', info['volt']) else None)
        pos = writeln('Rthrust =%9.3F'%(info['ref_thrust']), None)
        pos = write(' JOY', get_st_color(info['st_ct']))
        pos = write('MOTOR', get_st_color(info['st_mt']))
        pos = write('AutoHeight', get_st_color(info['st_ah']))
        pos = write('Smart Dir.', get_st_color(info['st_sd']))

        self.dc_uavinfo.Blit(0, 0, sz[0],sz[1], mem, 0, 0)
        
        # update bitmap_atti
        attiimg = self.UAVinfo.get_attitude_img()
        self.dc_attitude.DrawBitmap(util.cvimg_to_wxbmp(attiimg), 0, 0)        
    
    def update_GE(self, info):
        la = info['la']
        lo = info['lo']
        if self.GE_uninited:
            js = util.JSCODESINIT%(la,lo, info['height']*1.2)
            self.GE_uninited = False
        else:
            js = util.JSCODES%(la,lo, info['height']*1.2)
        self.browser_ge.RunScript(js)
    
    def get_hist_channel(self):
        if self.m_menuItem_track_hist_h.IsChecked():
            return [0]
        elif self.m_menuItem_track_hist_s.IsChecked():
            return [1]
        elif self.m_menuItem_track_hist_l.IsChecked():
            return [2]
    
    def enable_video_components(self, switch):
        for each in [self.m_button_video_window_show, 
                     self.m_bitmap_video,
                     self.m_button_record,
                     self.m_filePicker_output
                     ]:
            each.Enable(switch)  
        self.m_button_record.Enable(False)         
    
    def OnClose(self, event):
        print('Close window...')
        self.timer.Stop()
#         try:
#             self.camcap.release()
#         except AttributeError:
#             print('No camcap, release failed.')
        if self.m_button_toggle_xbee.is_running:
            self.close_xbee(self.m_button_toggle_xbee)
        if self.m_button_toggle_track_video.is_running:
            self.close_video(self.m_button_toggle_track_video)
        self.Destroy()