Exemple #1
0
class DataWindow:
    def __init__(self, name, data_queue):
        """
        Init functions that sets up the general shape and feel of the window

        :param name: Name of the main window
        :param data_queue: queue used to communicate with the radio
        """
        self.queue = data_queue
        self.bg_color = "#484949"
        frames_bg = "#969694"
        self.framesBg = frames_bg
        self.frames_bg = frames_bg
        self.time_bg = "#1e1e1e"
        self.yellow = "#f8fc16"
        self.total_rows = 18

        # Random Vars to init for draw()
        self.start_timer = None
        self.timer = None
        self.dataRocket = None
        self.dataRocket = None
        self.altGraph = None
        self.dataBalloon = None
        self.sixGraph = None
        self.control = None
        self.altitude_graph = None
        self.quality_checks = None
        self.stability = None
        self.stability_button = None
        self.packets_sent = None
        self.packets_received = None
        self.received_percentage = None
        self.warningLabel = None

        # Random Vars for init_graph_stuff()
        self.balloon_acc_xQ = None
        self.balloon_acc_yQ = None
        self.balloon_acc_zQ = None
        self.balloon_gyro_xQ = None
        self.balloon_gyro_yQ = None
        self.balloon_gyro_zQ = None
        self.rocket_acc_xQ = None
        self.rocket_acc_yQ = None
        self.rocket_acc_zQ = None
        self.rocket_gyro_xQ = None
        self.rocket_gyro_yQ = None
        self.rocket_gyro_zQ = None
        self.altitudeQ = None
        self.acc_gyro_graphs = None

        # Base file writing from program's execution directory
        program_path = os.path.dirname(os.path.realpath(__file__))
        self.status_log_path = os.path.join(program_path, "../logs/status.log")
        self.image_folder_path = os.path.join(program_path, "../res/img")

        self.name = name

        # Prevents the user from resizing the window too small
        self.name.minsize(round(self.name.winfo_screenwidth() / 2),
                          round(self.name.winfo_screenheight() / 2))

        # Set up
        self.test_mode = False
        self.abort_method = None
        self.radio = Module.get_instance(self)

        name.title("Ground Station Graphical User Interface v0.3-alpha")
        # name.iconbitmap(os.path.join(self.image_folder_path, "MyOrbital.ico"))

        # self.name.geometry('1000x600')
        self.name.configure(bg=self.bg_color)
        # name.attributes('-zoomed', True)
        # name.state('zoomed')
        # name.update_idletasks()

        # Set up GPIO pins for use, see documentation for pin layout
        # orange wire
        self.launch_signal = 11
        # yellow wire
        self.on_signal = 12
        # white wire
        self.gui_switch = 7

        GPIO.setmode(GPIO.BOARD)
        GPIO.setwarnings(False)
        GPIO.setup(self.launch_signal, GPIO.IN)
        GPIO.setup(self.on_signal, GPIO.OUT)
        GPIO.setup(self.gui_switch, GPIO.OUT)

        GPIO.output(self.on_signal, GPIO.HIGH)
        GPIO.output(self.on_signal, GPIO.LOW)
        GPIO.output(self.gui_switch, GPIO.LOW)

        GPIO.add_event_detect(11, GPIO.RISING, callback=self.launch)

        self.init_graph_stuff()
        self.draw()

        self.shutdown_timer = None

        # Running variable to see if program was terminated
        self.running = 1

    def draw(self):
        self.make_tool_bar()

        self.make_grid()

        # Make timer sections
        Label(self.name, text="Mission Clock:", font=('times', 16, 'bold'), bg=self.frames_bg). \
            grid(row=0, column=1, rowspan=2, columnspan=1, sticky=N + S + E + W)
        Label(self.name, text="Flight Clock:", font=('times', 16, 'bold'), bg=self.frames_bg). \
            grid(row=3, column=1, rowspan=2, columnspan=1, sticky=N + S + E + W)
        self.start_timer = Timer(self.name, 0, 2, 2, 2, self.time_bg)
        self.timer = Timer(self.name, 3, 2, 2, 2, self.time_bg)

        # Make data sections
        self.dataBalloon = Data(self.name, "Balloon Data", 6, 9,
                                self.frames_bg)

        # Config button styles
        ttk.Style().configure("yellow.TButton", background=self.yellow)

        # Place Graph buttons
        # self.init_graph_queues()

        self.altGraph = ttk.Button(self.name,
                                   text="Altitude",
                                   style="yellow.TButton",
                                   command=self.open_altitude_graph)
        self.sixGraph = ttk.Button(self.name,
                                   text="Direction",
                                   style="yellow.TButton",
                                   command=self.open_acc_gyro_graphs)

        self.altGraph.grid(column=6,
                           columnspan=4,
                           row=11,
                           rowspan=1,
                           sticky=N + S + E + W)
        self.sixGraph.grid(column=6,
                           columnspan=4,
                           row=12,
                           rowspan=1,
                           sticky=N + S + E + W)

        # Adds our logo
        logo = PhotoImage(file=os.path.join(self.image_folder_path,
                                            "orbital-logo-reduced.gif"))
        logo_label = Label(self.name, image=logo, bg=self.bg_color)
        logo_label.image = logo
        logo_label.grid(row=14,
                        column=6,
                        rowspan=3,
                        columnspan=4,
                        sticky=N + S + E + W)

        self.control = Control(self.name, 6, 2, 1, self.frames_bg)

        # Adds Radio Counters
        self.packets_sent = StatCounter(self.name, "Packets Sent", 1, 10,
                                        self.frames_bg)
        self.packets_received = StatCounter(self.name, "Packets Received", 2,
                                            10, self.frames_bg)

        # Create received percentage
        Label(self.name, text="Percent Received", font=('times', 12, 'underline'), bg=self.frames_bg). \
            grid(row=10, column=3, sticky=S + E + W)

        self.received_percentage = StringVar()
        self.calc_received_percentage()

        Label(self.name, textvariable=self.received_percentage, bg=self.frames_bg). \
            grid(row=11, column=3, sticky=N + E + W)

        # Place Quality Indicators and Labels
        self.quality_checks = [
            QualityCheck(self.name, "QDM", 1, 12, self.frames_bg),
            QualityCheck(self.name, "Ignition", 2, 12, self.frames_bg),
            QualityCheck(self.name, "Platform Stability", 1, 14,
                         self.frames_bg),
            QualityCheck(self.name, "GS Radio", 3, 12, self.frames_bg),
            QualityCheck(self.name, "Platform Radio", 3, 14, self.frames_bg),
        ]

        self.quality_checks[3].set_quality(self.radio.is_local_device_init)

        # Innit the warning label
        self.warningLabel = Label(self.name,
                                  text="WARNING: TEST MODE",
                                  bg="#ff0000",
                                  relief=RAISED,
                                  font=("Times", 30, "bold"))

        # Create Button for Stability Control
        self.stability = False
        self.stability_button = ttk.Button(
            text="Turn On Stabilization",
            style="yellow.TButton",
            command=self.stability_message_callback)
        self.stability_button.grid(column=1,
                                   columnspan=3,
                                   row=16,
                                   sticky=N + S + E + W)

        # Binds verify and control buttons
        self.control.verify_button.config(command=self.verify_message_callback)
        self.control.abort_button.config(command=self.abort_message_callback)

    def init_graph_stuff(self):
        """
        Sets up the graphs
        :return: None
        """
        # Create several queue that holds the number for each line in every graph
        self.balloon_acc_xQ = queue.Queue()
        self.balloon_acc_yQ = queue.Queue()
        self.balloon_acc_zQ = queue.Queue()
        self.balloon_gyro_xQ = queue.Queue()
        self.balloon_gyro_yQ = queue.Queue()
        self.balloon_gyro_zQ = queue.Queue()
        self.rocket_acc_xQ = queue.Queue()
        self.rocket_acc_yQ = queue.Queue()
        self.rocket_acc_zQ = queue.Queue()
        self.rocket_gyro_xQ = queue.Queue()
        self.rocket_gyro_yQ = queue.Queue()
        self.rocket_gyro_zQ = queue.Queue()
        self.altitudeQ = queue.Queue()

        amount_of_point_to_graph = 20
        for i in range(0, amount_of_point_to_graph):
            self.balloon_acc_xQ.put(0)
            self.balloon_acc_yQ.put(0)
            self.balloon_acc_zQ.put(0)
            self.balloon_gyro_xQ.put(0)
            self.balloon_gyro_yQ.put(0)
            self.balloon_gyro_zQ.put(0)
            self.rocket_acc_xQ.put(0)
            self.rocket_acc_yQ.put(0)
            self.rocket_acc_zQ.put(0)
            self.rocket_gyro_xQ.put(0)
            self.rocket_gyro_yQ.put(0)
            self.rocket_gyro_zQ.put(0)
            self.altitudeQ.put(0)

        self.altitude_graph = None
        self.acc_gyro_graphs = None

    def make_tool_bar(self):
        """
        Sets up the labels and buttons in the tool bar and binds them to respective functions
        :return: None
        """
        menu_bar = Menu(self.name)

        file_menu = Menu(menu_bar, tearoff=0)
        program_menu = Menu(menu_bar, tearoff=0)
        help_menu = Menu(menu_bar, tearoff=0)
        # test_menu = Menu(menu_bar, tearoff=0)

        menu_bar.add_cascade(label="File", menu=file_menu)
        menu_bar.add_cascade(label="Program", menu=program_menu)
        menu_bar.add_cascade(label="Help", menu=help_menu)
        # menu_bar.add_cascade(label="Test", menu=test_menu)

        file_menu.add_command(label="Restart", command=self.restart_program)

        file_menu.add_separator()
        file_menu.add_command(label="Exit", command=self.close)

        program_menu.add_command(label="Start Mission",
                                 command=self.start_mission)
        program_menu.add_separator()
        program_menu.add_command(label="Toggle Test Mode",
                                 command=self.alter_test_mode)
        program_menu.add_command(label="Log", command=self.log_menu)
        program_menu.add_command(label="Reset Data",
                                 command=self.reset_variables_window)
        program_menu.add_command(label="Reset Radio", command=self.reset_radio)
        program_menu.add_command(label="Change Address",
                                 command=self.change_radio_address_callback)
        program_menu.add_command(label="Manual Override",
                                 command=self.manual_override_callback)

        help_menu.add_command(label="Help Index", command=self.help_window)
        # help_menu.add_separator()
        help_menu.add_command(label="About",
                              command=self.about_menu)  # TODO: Put this back

        # test_menu.add_command(label="Launch", command=self.test_launch)
        # test_menu.add_command(label="Abort", command=self.test_abort)
        # test_menu.add_command(label="Stability On", command=self.test_stability)

        self.name.config(menu=menu_bar)

    def make_grid(self):
        """
        Sets the grid for the window, sets the background color for cells and determines which cells will resize
        to fill the window space
        :return: None
        """
        total_rows = self.total_rows
        total_columns = 11

        my_rows = range(0, total_rows)
        my_columns = range(0, total_columns)
        control_col = range(1, 4)

        for column in my_columns:
            self.name.columnconfigure(column, weight=1)

        for row in my_rows:
            self.name.rowconfigure(row, weight=4, uniform=1)

        self.name.rowconfigure(2, weight=1, uniform=0)
        self.name.rowconfigure(5, weight=1, uniform=0)

        for col in control_col:
            self.name.columnconfigure(col, minsize=100)
            for row in range(6, 16):
                color_frame = Label(self.name, bg=self.framesBg)
                color_frame.grid(row=row, column=col, sticky=N + S + E + W)

    def start_mission(self):
        """
        Method is called when start mission in tool bar is selected.
        Starts the mission clock, and enables verify and abort buttons
        Sends test command

        :return: None
        """
        if not self.start_timer.clock_run:
            self.start_timer.start = time.time()
            self.start_timer.clock_run = True
            self.start_timer.tick()

        self.control.verify_button.state(["!disabled"])
        self.control.abort_button.state(["!disabled"])

        Comm.get_instance(self).flight()

        self.shutdown_timer = ShutdownTimer(300, self.time_out)

    def launch(self):
        """
        Method is called when GPIO Pin 11 gets a rising edge.
        Checks if that mission has not started and mission is verified
        Starts the flight clock
        Changes status to LAUNCHED
        :return: None
        """
        # Using self.timer.clock_run as a launched bool
        # Not sure if there is something more proper to use
        if not self.timer.clock_run and self.control.mission_status == Status.VERIFIED:
            c = Comm.get_instance(self)
            c.send("Ignition")

            # Kind of puts the whole thread to sleep for 5 secs
            # But I think this is what the issue is asking for
            # time.sleep(5)

            self.timer.start = time.time()
            self.timer.clock_run = True
            self.timer.delay_tick()

            self.control.mission_status = Status.LAUNCHED
            self.control.verify_button.config(text="VERIFY")
            self.control.verify_button.config(state='disabled')

            self.log(self.control.mission_status)
            self.control.change_status_display(self.control.mission_status)

    def reset_variables_window(self):
        """
        Callback window asking the user if they really want to reset the data.
        If yes, logs a reset, and resets both balloon and rocket data
        :return: None
        """
        # Creates a pop up window that asks if you are sure that you want to rest the variables.
        # If yes then all the variables are reset
        reset_window = messagebox.askokcancel(
            "Reset All Variables?",
            "Are you sure you want to reset all variables?")
        if reset_window:
            self.log(Status.RESET)
            self.dataBalloon.reset_variables()
            self.dataRocket.reset_variables()

    def log(self, status):
        """
        Records the data in status.log
        :param status: reason why the data was logged
        :return: None
        """
        fo = open(self.status_log_path, "a")

        current_date = datetime.datetime.fromtimestamp(
            time.time()).strftime('%Y-%m-%d %H:%M:%S')
        if status == Status.ABORT:
            fo.write("-------MISSION ABORTED-------\n")
        elif status == Status.VERIFIED:
            fo.write("-------STATUS VERIFIED-------\n")
        elif status == Status.MANUAL:
            fo.write("-----MANUAL LOG INVOKED------\n")
        elif status == Status.RESET:
            fo.write("-------VARIABLES RESET-------\n")
        elif status == Status.RESTART:
            fo.write("-------PROGRAM RESTART-------\n")
        elif status == Status.NOT_VERIFIED:
            fo.write("-----STATUS NOT VERIFIED-----\n")
        elif status == Status.LAUNCHED:
            fo.write("-------LAUNCHED-------\n")
        elif status == Status.TIMEOUT:
            fo.write("-------RADIO TIME OUT-------\n")

        fo.write("DATE:" + current_date + "\n")
        fo.write("MISSION START TIMESTAMP:" +
                 repr(self.start_timer.current_time) + "\n")
        fo.write("LAUNCH START TIMESTAMP:" + repr(self.timer.current_time) +
                 "\n")
        fo.write("*****************************\n")
        fo.write("----------LOGS START---------\n")
        fo.write("----------BALLOON DATA-------\n")
        fo.write("Longitude = " + repr(self.dataBalloon.longitude_data) + "\n")
        fo.write("Latitude = " + repr(self.dataBalloon.latitude_data) + "\n")
        fo.write("Gyro(X) = " + repr(self.dataBalloon.gyroX_data) + "\n")
        fo.write("Gyro(Y) = " + repr(self.dataBalloon.gyroY_data) + "\n")
        fo.write("Gyro(Z) = " + repr(self.dataBalloon.gyroZ_data) + "\n")
        fo.write("Temperature = " + repr(self.dataBalloon.temperature_data) +
                 "\n")
        fo.write("Acceleration(X) = " + repr(self.dataBalloon.accelX_data) +
                 "\n")
        fo.write("Acceleration(Y) = " + repr(self.dataBalloon.accelY_data) +
                 "\n")
        fo.write("Acceleration(Z) = " + repr(self.dataBalloon.accelZ_data) +
                 "\n")
        fo.write("----------LOGS END-----------\n")
        fo.write("-----------------------------\n\n")
        fo.close()

    def log_menu(self):
        """
        Logs data manually and a Pop up window informing user that data has been logged manually
        :return: None
        """
        log_window = Toplevel(self.name)
        log_window.title("Manual Log")
        logged_label = Label(
            log_window,
            text="The current variables have been logged in 'logs/status.log'")
        logged_label.pack()
        button = Button(log_window,
                        text="Close",
                        command=lambda: log_window.destroy())
        button.pack()
        self.log(Status.MANUAL)

    def about_menu(self):
        """
        Pop up window with about information
        :return: None
        """

        about_text = "Ground Station Graphical User Interface Version 0.3-alpha\n\n" \
                     "Author: Ken Sodetz, Matt Drozt, Jay Rixie, Emanuel Pituch, Connor Todd\n" \
                     "Since: 11/27/2018\n\n" \
                     "Created for Purdue Orbital Electrical and Software Sub team\n\n" \
                     "Parses and displays data from the a Raspberry Pi 3 to verbosely display all\n" \
                     "pertinent system data"

        about_window = Toplevel(self.name)
        about_window.title("About")
        about_window.resizable(width=False, height=False)
        text = Text(about_window)
        text.insert(INSERT, about_text)
        text.config(state=DISABLED)
        text.pack()
        self.name.img = img = PhotoImage(file=os.path.join(
            self.image_folder_path, "orbital-logo-reduced.gif"))
        logo = Label(about_window, image=img)
        logo.place(x=0, y=200)
        button = Button(about_window,
                        text="Close",
                        command=lambda: about_window.destroy())
        button.pack()

    def help_window(self):
        """
        Opens a window with a single button to close it. Used as a place holder for help index.
        Needs to be fleshed out or gotten rid of
        :return: None
        """
        file_window = Toplevel(self.name)
        button = Button(file_window,
                        text="Close",
                        command=lambda: file_window.destroy())
        button.pack()

    def restart_program(self):
        """
        Closes and restarts the program
        :return: None
        """
        python = sys.executable
        GPIO.output(self.gui_switch, GPIO.LOW)
        GPIO.cleanup()
        self.log(Status.RESTART)
        os.execl(python, python, *sys.argv)

    def alter_test_mode(self):

        # TODO use above mode defined in CommunicationDriver.py
        self.test_mode = not self.test_mode

        self.init_graph_stuff()
        self.dataBalloon.reset_variables()
        self.control.reset_status()
        self.timer.reset()
        self.start_timer.reset()
        self.packets_sent.reset()
        self.packets_received.reset()
        self.calc_received_percentage()
        c = Comm.get_instance(self)
        c.reset_counters()

        for check in self.quality_checks:
            check.reset_quality()

        if self.test_mode:
            self.name.rowconfigure(19, weight=2)
            self.warningLabel.grid(row=19,
                                   column=0,
                                   columnspan=11,
                                   sticky=N + S + E + W)

        else:
            self.name.rowconfigure(19, weight=2)
            self.warningLabel.grid_forget()

        if c.get_mode() == Mode.STANDBY:
            c.testing()

        elif c.get_mode() == Mode.TESTING:
            c.standby()

        else:
            print("\n*** CANNOT ENTER TEST MODE DURING FLIGHT ***")

    def is_test_mode(self):
        try:
            c = Comm.get_instance(self)
            return c.get_mode() == Mode.TESTING
        except Exception as e:
            print("Test Mode Error")
            print(e)

    def manual_override_callback(self):
        random_int = ""
        for i in range(6):
            random_int = random_int + random.SystemRandom().choice(
                string.digits)

        s = simpledialog.askstring(
            "DANGER: Manual Override",
            "Please note that manual overrides are dangerous and should only be used in "
            +
            "a worst case scenario.\nPlease check with the launch director before proceeding."
            + "\n\n" + "To override please enter the following number: \n\n" +
            random_int)
        if s == random_int:
            self.launch()
            messagebox.showinfo("SUCCESS: Preforming Override",
                                "Manual Override was Successful")
        elif s is not None:
            messagebox.showerror("ERROR: Bad Input",
                                 "Strings did not match.\nStopping Override.")
        else:
            messagebox.showerror(
                "ERROR: Conditions Not Met",
                "Conditions not met for launch. Cancelling Override")

    def change_radio_address_callback(self):
        try:
            c = Comm.get_instance(self)
            a = simpledialog.askstring(
                "Change Radio Address",
                "Type a hex number (1 - 9, A - F) for the radio address of the recieving radio"
                + "\n\n" + "The current address is: " +
                str(c.get_remote_node_address()))

            if a is None:
                return

            # TODO: Probably a better way to check if it is hex
            is_hex = True
            hex_char_set = [
                '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
                'C', 'D', 'E', 'F'
            ]
            for char in a:
                if char not in hex_char_set:
                    is_hex = False

            if len(a) != 16 or not is_hex:
                messagebox.showerror(
                    "ERROR: Invalid Address",
                    "The provided hex number was invalid\n\n" +
                    "Reverting to initial address")
            else:
                c.set_remote_node_address(a)
        except Exception as e:
            messagebox.showerror(
                "ERROR: Something went wrong",
                "Something went wrong\n\nNot Changing the Address.")
            print(e)

    def verify_message_callback(self):
        """
        Call back for verifying and un-verifying the mission. Changes mission status and buttons as necessary
        :return: None
        """
        if self.control.mission_status == Status.NOT_VERIFIED:
            verify_response = messagebox.askyesno(
                "Verify Mission?", "Do you want to verify the mission")
            if verify_response:
                self.control.mission_status = Status.VERIFIED
                self.control.change_status_display(self.control.mission_status)
                self.log(self.control.mission_status)
                GPIO.output(self.gui_switch, GPIO.HIGH)
                # self.timer.start = time.time()
                # self.timer.clock_run = True
                # self.timer.tick()
                self.control.verify_button.config(text="UNVERIFY")

        elif self.control.mission_status == Status.VERIFIED:
            verify_response = messagebox.askyesno(
                "Unverify Mission?", "Do you want to unverify the mission")
            if verify_response:
                self.control.mission_status = Status.NOT_VERIFIED
                self.control.change_status_display(self.control.mission_status)
                self.log(self.control.mission_status)
                # self.timer.clock_run = False
                self.control.verify_button.config(text="VERIFY")

        elif self.control.mission_status == Status.ABORT:
            verify_response = messagebox.askyesno(
                "Verify Mission?", "Do you want to verify the mission")
            if verify_response:
                self.control.mission_status = Status.VERIFIED
                self.control.change_status_display(self.control.mission_status)
                self.log(self.control.mission_status)
                # self.timer.start = time.time()
                # self.timer.clock_run = True
                # self.timer.tick()
                self.control.verify_button.config(text="UNVERIFY")

    def stability_message_callback(self):
        """
        Makes sure user wants to turn on/off stabilization
        :return: None
        """
        if self.stability:
            if messagebox.askyesno("Turn off Stabilization",
                                   "Do you want to turn off stabilization"):

                try:
                    c = Comm.get_instance(self)
                    if c.send("Stabilization off"):
                        self.stability_button.config(
                            text="Turn On Stabilization")
                        self.stability = not self.stability
                        self.packets_sent.set_count(c.get_packets_sent())
                        self.packets_received.set_count(
                            c.get_packets_received())
                        self.calc_received_percentage()
                    else:
                        self.quality_checks[4].set_quality(0)
                        messagebox.showerror("ERROR: Command Not Sent",
                                             "Command Not Sent")
                        c.packets_sent -= 1

                except Exception as e:
                    print("Stabilization Error")
                    print(e)

        else:
            if messagebox.askyesno("Turn on Stabilization",
                                   "Do you want to turn on stabilization"):

                try:
                    c = Comm.get_instance(self)
                    if c.send("Stabilization on"):
                        self.stability_button.config(
                            text="Turn Off Stabilization")
                        self.stability = not self.stability
                        self.packets_sent.set_count(c.get_packets_sent())
                        self.packets_received.set_count(
                            c.get_packets_received())
                        self.calc_received_percentage()
                    else:
                        self.quality_checks[4].set_quality(0)
                        messagebox.showerror("ERROR: Command Not Sent",
                                             "Command Not Sent")
                        c.packets_sent -= 1

                except Exception as e:
                    print("Stabilization Error")
                    print(e)

    def abort_message_callback(self):
        """
        Callback if the user decides to abort the mission
        :return: None
        """
        abort_response = messagebox.askyesno(
            "Abort Mission?", "Do you really want to abort the mission?")
        if abort_response:
            self.select_qdm()

    def test_launch(self):
        try:
            c = Comm.get_instance(self)
            m = c.get_mode()

            c.testing()
            c.send("launch")
            self.packets_sent.set_count(c.get_packets_sent())
            self.packets_received.set_count(c.get_packets_received())
            self.calc_received_percentage()
            c.set_mode(m)
        except Exception as e:
            print("Test Launch Error")
            print(e)

    def test_abort(self):
        try:
            c = Comm.get_instance(self)
            m = c.get_mode()

            c.testing()
            c.send("abort")
            self.packets_sent.set_count(c.get_packets_sent())
            self.packets_received.set_count(c.get_packets_received())
            self.calc_received_percentage()
            c.set_mode(m)
        except Exception as e:
            print("Test Abort Error")
            print(e)

    def test_stability(self):
        try:
            c = Comm.get_instance(self)
            m = c.get_mode()

            c.testing()
            c.send("stability")
            self.packets_sent.set_count(c.get_packets_sent())
            self.packets_received.set_count(c.get_packets_received())
            self.calc_received_percentage()
            c.set_mode(m)
        except Exception as e:
            print("Test Stability Error")
            print(e)

    def select_cdm(self):
        # TODO: Are we using CDM at all??? Get rid of?
        c = Comm.get_instance(self)
        c.flight()
        c.send("cdm")
        self.packets_sent.set_count(c.get_packets_sent())
        self.packets_received.set_count(c.get_packets_received())
        self.calc_received_percentage()

        self.abort_method = "CDM"
        self.control.mission_status = Status.ABORT
        self.log(self.control.mission_status)
        self.timer.clock_run = False
        self.control.verify_button.config(text="VERIFY")
        self.control.change_status_display(self.control.mission_status)
        GPIO.output(self.gui_switch, GPIO.LOW)

    def select_qdm(self):
        """
        Method called sending a qdm command and logging the incident
        :return: None
        """

        print("QDM")
        # TODO Make Comms Global
        try:
            c = Comm.get_instance(self)
            c.flight()
            c.send("qdm")
            self.packets_sent.set_count(c.get_packets_sent())
            self.packets_received.set_count(c.get_packets_received())
            self.calc_received_percentage()
        except Exception as e:
            print(e)

        self.abort_method = "QDM"
        self.control.mission_status = Status.ABORT
        # self.timer.clock_run = False
        self.control.verify_button.config(text="VERIFY")
        self.control.verify_button.config(state='disabled')
        self.log(self.control.mission_status)
        self.control.change_status_display(self.control.mission_status)
        GPIO.output(self.gui_switch, GPIO.LOW)

    def time_out(self):
        # TODO: Needs a lot of testing
        self.control.mission_status = Status.TIMEOUT
        self.log(self.control.mission_status)
        self.control.change_status_display(self.control.mission_status)
        print("Mission Timeout")

    def process_incoming(self):
        """
        Updates data
        :return: None
        """
        # Process data in queue
        while self.queue.qsize():
            self.quality_checks[4].set_quality(1)
            try:
                if self.shutdown_timer is not None:
                    self.shutdown_timer.stop()
                self.shutdown_timer = ShutdownTimer(300, self.time_out)
                data_json = self.queue.get()
                print(data_json)

                origin = data_json["origin"]

                if origin == "balloon":
                    data = self.dataBalloon
                elif origin == "status":
                    self.quality_checks[0].set_quality(data_json["QDM"])
                    self.quality_checks[1].set_quality(data_json["Ignition"])
                    self.quality_checks[2].set_quality(
                        data_json["Stabilization"])
                    self.quality_checks[4].set_quality(data_json["PlatRadio"])

                    return
                else:
                    print("JSON ORIGIN INCORRECT")
                    return

                gps_json = data_json["GPS"]
                data.longitude_data = gps_json["long"]
                data.latitude_data = gps_json["lat"]
                data.altitude_data = gps_json["alt"]

                gyro_json = data_json["gyro"]
                data.gyroX_data = gyro_json["x"]
                data.gyroY_data = gyro_json["y"]
                data.gyroZ_data = gyro_json["z"]

                data.temperature_data = data_json["temp"]

                acc_json = data_json["acc"]
                data.accelX_data = acc_json["x"]
                data.accelY_data = acc_json["y"]
                data.accelZ_data = acc_json["z"]

                data.display_variables()

                # insert it into the queues
                self.altitudeQ.get()
                self.altitudeQ.put(data.altitude_data)

                if self.altitude_graph is not None:
                    self.altitude_graph.update_altitude(self.altitudeQ)

                elif origin == "balloon":
                    self.balloon_acc_xQ.get()
                    self.balloon_acc_yQ.get()
                    self.balloon_acc_zQ.get()
                    self.balloon_gyro_xQ.get()
                    self.balloon_gyro_yQ.get()
                    self.balloon_gyro_zQ.get()
                    self.balloon_acc_xQ.put(data.accelX_data)
                    self.balloon_acc_yQ.put(data.accelY_data)
                    self.balloon_acc_zQ.put(data.accelZ_data)
                    self.balloon_gyro_xQ.put(data.gyroX_data)
                    self.balloon_gyro_yQ.put(data.gyroY_data)
                    self.balloon_gyro_zQ.put(data.gyroZ_data)
                    if self.acc_gyro_graphs is not None:
                        self.acc_gyro_graphs.update_balloon_acc(
                            self.balloon_acc_xQ, self.balloon_acc_yQ,
                            self.balloon_acc_zQ)
                        self.acc_gyro_graphs.update_balloon_gyro(
                            self.balloon_gyro_xQ, self.balloon_gyro_yQ,
                            self.balloon_gyro_zQ)

                        # Set the data variables equal to the corresponding json entries
                        # self.data.temperature_data = data_json["temperature"]
                        # self.data.pressure_data = data_json["pressure"]
                        # self.data.humidity_data = data_json["humidity"]
                        # self.data.altitude_data = data_json["altitude"]
                        # self.data.direction_data = data_json["direction"]
                        # self.data.acceleration_data = data_json["acceleration"]
                        # self.data.velocity_data = data_json["velocity"]
                        # self.data.user_angle_data = data_json["user_angle"]
                        # Reload variables

            except queue.Empty:
                pass

    def close(self):
        """
        Closes the window
        :return: None
        """
        self.running = 0

    def open_altitude_graph(self):
        """
        Opens and instance of the altitude graph
        :return:None
        """
        self.altitude_graph = AltitudeGraph()
        self.altitude_graph.update_altitude(self.altitudeQ)

    def open_acc_gyro_graphs(self):
        """
        Opens an instance of the acceleration and gyro graphs
        :return: None
        """
        self.acc_gyro_graphs = AccelerometerGyroGraphs()

        self.acc_gyro_graphs.update_balloon_acc(self.balloon_acc_xQ,
                                                self.balloon_acc_yQ,
                                                self.balloon_acc_zQ)
        self.acc_gyro_graphs.update_balloon_gyro(self.balloon_gyro_xQ,
                                                 self.balloon_gyro_yQ,
                                                 self.balloon_gyro_zQ)

    def reset_radio(self):
        """
        Resets Radio
        :return: None
        """
        self.radio.reset_radio()

    def calc_received_percentage(self):
        """
        Calculates the received rate of the packets using the counter numbers
        :return: None
        """
        if self.packets_sent.get_count() == 0:
            self.received_percentage.set("NaN")
            return

        self.received_percentage.set(
            round(
                self.packets_received.get_count() * 100 /
                self.packets_sent.get_count(), 2))