Exemple #1
0
def start_udp_receiver(bad_things_queue, state_queue, sm_pipe):
    try:
        recv_class = UDPRecvClass(bad_things_queue, state_queue, sm_pipe)
        recv_class.start()
    except Exception as e:
        bad_things_queue.put(
            BadThing(sys.exc_info(), str(e), event=BAD_EVENTS.UDP_RECV_ERROR))
Exemple #2
0
def start_tcp(bad_things_queue, state_queue, sm_pipe):
    try:
        tcp_class = TCPClass(bad_things_queue, state_queue, sm_pipe)
        tcp_class.start()
    except Exception as e:
        bad_things_queue.put(
            BadThing(sys.exc_info(), str(e), event=BAD_EVENTS.TCP_ERROR))
Exemple #3
0
def start_udp_sender(bad_things_queue, state_queue, sm_pipe):
    try:
        send_class = UDPSendClass(bad_things_queue, state_queue, sm_pipe)
        send_class.start()
    except Exception as e:
        bad_things_queue.put(
            BadThing(sys.exc_info(), str(e), event=BAD_EVENTS.UDP_SEND_ERROR))
Exemple #4
0
        async def main_loop():
            exec_count = 0
            while not terminated and (exception_cell[0] is None) and (
                    max_iter is None or exec_count < max_iter):
                next_call = loop.time(
                ) + 1. / RUNTIME_CONFIG.STUDENT_CODE_HZ.value
                studentCode.Robot._get_all_sensors()  # pylint: disable=protected-access
                studentCode.Gamepad._get_gamepad()  # pylint: disable=protected-access
                check_timed_out(main_fn)

                # Throttle sending print statements
                if (exec_count % 5) == 0:
                    studentCode.Robot._send_prints()  # pylint: disable=protected-access

                sleep_time = max(next_call - loop.time(), 0.)
                state_queue.put([SM_COMMANDS.STUDENT_MAIN_OK, []])
                exec_count += 1
                await asyncio.sleep(sleep_time)
            if exception_cell[0] is not None:
                raise exception_cell[0]  # pylint: disable=raising-bad-type
            if not terminated:
                bad_things_queue.put(
                    BadThing(sys.exc_info(),
                             "Process Ended",
                             event=BAD_EVENTS.END_EVENT))
Exemple #5
0
def start_state_manager(bad_things_queue, state_queue, runtime_pipe):
    try:
        state_manager = StateManager(bad_things_queue, state_queue,
                                     runtime_pipe)
        state_manager.start()
    except Exception as e:
        bad_things_queue.put(
            BadThing(sys.exc_info(),
                     str(e),
                     event=BAD_EVENTS.STATE_MANAGER_CRASH))
Exemple #6
0
def start_hibike(bad_things_queue, state_queue, pipe):
    # bad_things_queue - queue to runtime
    # state_queue - queue to StateManager
    # pipe - pipe from statemanager
    def add_paths():
        """Modify sys.path so we can find hibike.
        """
        path = os.path.dirname(os.path.abspath(__file__))
        parent_path = path.rstrip("runtime")
        hibike = os.path.join(parent_path, "hibike")
        sys.path.insert(1, hibike)

    try:
        add_paths()
        import hibike_process  # pylint: disable=import-error
        hibike_process.hibike_process(bad_things_queue, state_queue, pipe)
    except Exception as e:
        bad_things_queue.put(BadThing(sys.exc_info(), str(e)))
Exemple #7
0
def runtime(test_name=""):  # pylint: disable=too-many-statements
    test_mode = test_name != ""
    max_iter = 3 if test_mode else None

    def non_test_mode_print(*args):
        """Prints only if we are NOT in test_mode"""
        if not test_mode:
            print(args)

    bad_things_queue = multiprocessing.Queue()
    state_queue = multiprocessing.Queue()
    spawn_process = process_factory(bad_things_queue, state_queue)
    restart_count = 0
    emergency_stopped = False

    try:
        spawn_process(PROCESS_NAMES.STATE_MANAGER, start_state_manager)
        spawn_process(PROCESS_NAMES.UDP_RECEIVE_PROCESS, start_udp_receiver)
        spawn_process(PROCESS_NAMES.HIBIKE, start_hibike)

        def fc_server_target():
            fc_server = FieldControlServer(state_queue)
            # pylint: disable=no-member
            asyncio.run(run_field_control_server(fc_server, '0.0.0.0', 6020))

        fc_thread = threading.Thread(target=fc_server_target, daemon=True)
        fc_thread.start()
        control_state = "idle"
        dawn_connected = False

        while True:
            if test_mode:
                # Automatically enter telop mode when running tests
                bad_things_queue.put(
                    BadThing(sys.exc_info(),
                             "Sending initial command to enter teleop",
                             event=BAD_EVENTS.ENTER_TELEOP,
                             printStackTrace=False))
            if restart_count >= 3:
                non_test_mode_print(
                    RUNTIME_CONFIG.DEBUG_DELIMITER_STRING.value)
                non_test_mode_print("Too many restarts, terminating")
                break
            if emergency_stopped:
                non_test_mode_print(
                    RUNTIME_CONFIG.DEBUG_DELIMITER_STRING.value)
                non_test_mode_print("terminating due to E-Stop")
                break
            non_test_mode_print(RUNTIME_CONFIG.DEBUG_DELIMITER_STRING.value)
            non_test_mode_print("Starting studentCode attempt: %s" %
                                (restart_count, ))
            while True:
                new_bad_thing = bad_things_queue.get(block=True)
                if new_bad_thing.event == BAD_EVENTS.NEW_IP and not dawn_connected:
                    spawn_process(PROCESS_NAMES.UDP_SEND_PROCESS,
                                  start_udp_sender)
                    spawn_process(PROCESS_NAMES.TCP_PROCESS, start_tcp)
                    dawn_connected = True
                    continue
                elif new_bad_thing.event == BAD_EVENTS.DAWN_DISCONNECTED and dawn_connected:
                    terminate_process(PROCESS_NAMES.UDP_RECEIVE_PROCESS)
                    terminate_process(PROCESS_NAMES.UDP_SEND_PROCESS)
                    terminate_process(PROCESS_NAMES.TCP_PROCESS)
                    spawn_process(PROCESS_NAMES.UDP_RECEIVE_PROCESS,
                                  start_udp_receiver)
                    dawn_connected = False
                    control_state = "idle"
                    break
                elif new_bad_thing.event == BAD_EVENTS.ENTER_TELEOP and control_state != "teleop":
                    terminate_process(PROCESS_NAMES.STUDENT_CODE)
                    name = test_name or "teleop"
                    spawn_process(PROCESS_NAMES.STUDENT_CODE, run_student_code,
                                  name, max_iter)
                    control_state = "teleop"
                    continue
                elif new_bad_thing.event == BAD_EVENTS.ENTER_AUTO and control_state != "auto":
                    terminate_process(PROCESS_NAMES.STUDENT_CODE)
                    spawn_process(PROCESS_NAMES.STUDENT_CODE, run_student_code,
                                  "autonomous")
                    control_state = "auto"
                    continue
                elif new_bad_thing.event == BAD_EVENTS.ENTER_IDLE and control_state != "idle":
                    control_state = "idle"
                    break
                print(new_bad_thing.event)
                non_test_mode_print(new_bad_thing.data)
                if new_bad_thing.event in restartEvents:
                    state_queue.put([
                        SM_COMMANDS.SEND_CONSOLE,
                        [new_bad_thing.getStudentError()]
                    ])
                    control_state = "idle"
                    if test_mode:
                        restart_count += 1
                    if not emergency_stopped and new_bad_thing.event is BAD_EVENTS.EMERGENCY_STOP:
                        emergency_stopped = True
                    break
            if test_mode:
                state_queue.put([SM_COMMANDS.RESET, []])
            terminate_process(PROCESS_NAMES.STUDENT_CODE)
            state_queue.put([
                SM_COMMANDS.SET_VAL,
                [
                    runtime_pb2.RuntimeData.STUDENT_STOPPED,
                    ["studentCodeState"], False
                ]
            ])
            state_queue.put([SM_COMMANDS.END_STUDENT_CODE, []])
            state_queue.put([HIBIKE_COMMANDS.DISABLE, []])
        non_test_mode_print(RUNTIME_CONFIG.DEBUG_DELIMITER_STRING.value)
        print("Funtime Runtime is done having fun.")
        print("TERMINATING")
    except Exception as e:
        print(RUNTIME_CONFIG.DEBUG_DELIMITER_STRING.value)
        print("Funtime Runtime had too much fun.")
        print(e)
        print("".join(traceback.format_tb(sys.exc_info()[2])))
Exemple #8
0
def run_student_code(bad_things_queue,
                     state_queue,
                     pipe,
                     test_name="",
                     max_iter=None):
    try:
        terminated = False

        def sig_term_handler(*_):
            nonlocal terminated
            terminated = True

        signal.signal(signal.SIGTERM, sig_term_handler)

        def timed_out_handler(*_):
            raise TimeoutError("studentCode timed out")

        signal.signal(signal.SIGALRM, timed_out_handler)

        def check_timed_out(func, *args):
            signal.alarm(RUNTIME_CONFIG.STUDENT_CODE_TIMELIMIT.value)
            func(*args)
            signal.alarm(0)

        signal.alarm(RUNTIME_CONFIG.STUDENT_CODE_TIMELIMIT.value)
        try:
            import studentCode
        except SyntaxError as e:
            raise RuntimeError("Student code has a syntax error: {}".format(e))
        signal.alarm(0)

        if test_name != "":
            test_name += "_"
        try:
            setup_fn = getattr(studentCode, test_name + "setup")
        except AttributeError:
            raise RuntimeError(
                "Student code failed to define '{}'".format(test_name +
                                                            "setup"))
        try:
            main_fn = getattr(studentCode, test_name + "main")
        except AttributeError:
            raise RuntimeError(
                "Student code failed to define '{}'".format(test_name +
                                                            "main"))

        ensure_is_function(test_name + "setup", setup_fn)
        ensure_is_function(test_name + "main", main_fn)
        ensure_not_overridden(studentCode, "Robot")

        studentCode.Robot = Robot(state_queue, pipe)
        studentCode.Gamepad = Gamepad(state_queue, pipe)
        studentCode.Field = Field(state_queue, pipe)
        studentCode.Actions = Actions
        studentCode.print = studentCode.Robot._print  # pylint: disable=protected-access

        # remapping for non-class student API commands
        studentCode.get_gamepad_value = studentCode.Gamepad.get_value
        studentCode.get_robot_value = studentCode.Robot.get_value
        studentCode.set_robot_value = studentCode.Robot.set_value
        studentCode.is_robot_running = studentCode.Robot.is_running
        studentCode.run_async = studentCode.Robot.run
        studentCode.sleep_duration = studentCode.Actions.sleep

        check_timed_out(setup_fn)
        exception_cell = [None]
        clarify_coroutine_warnings(exception_cell)

        async def main_loop():
            exec_count = 0
            while not terminated and (exception_cell[0] is None) and (
                    max_iter is None or exec_count < max_iter):
                next_call = loop.time(
                ) + 1. / RUNTIME_CONFIG.STUDENT_CODE_HZ.value
                studentCode.Robot._get_all_sensors()  # pylint: disable=protected-access
                studentCode.Gamepad._get_gamepad()  # pylint: disable=protected-access
                check_timed_out(main_fn)

                # Throttle sending print statements
                if (exec_count % 5) == 0:
                    studentCode.Robot._send_prints()  # pylint: disable=protected-access

                sleep_time = max(next_call - loop.time(), 0.)
                state_queue.put([SM_COMMANDS.STUDENT_MAIN_OK, []])
                exec_count += 1
                await asyncio.sleep(sleep_time)
            if exception_cell[0] is not None:
                raise exception_cell[0]  # pylint: disable=raising-bad-type
            if not terminated:
                bad_things_queue.put(
                    BadThing(sys.exc_info(),
                             "Process Ended",
                             event=BAD_EVENTS.END_EVENT))

        loop = asyncio.get_event_loop()

        def my_exception_handler(_loop, context):
            if exception_cell[0] is None:
                exception_cell[0] = context["exception"]

        loop.set_exception_handler(my_exception_handler)
        loop.run_until_complete(main_loop())

    except TimeoutError:
        event = BAD_EVENTS.STUDENT_CODE_TIMEOUT
        bad_things_queue.put(BadThing(sys.exc_info(), event.value,
                                      event=event))
    except StudentAPIError:
        event = BAD_EVENTS.STUDENT_CODE_VALUE_ERROR
        bad_things_queue.put(BadThing(sys.exc_info(), event.value,
                                      event=event))
    except Exception as e:  # something broke in student code
        bad_things_queue.put(
            BadThing(sys.exc_info(),
                     str(e),
                     event=BAD_EVENTS.STUDENT_CODE_ERROR))
Exemple #9
0
def run_student_code(bad_things_queue,
                     state_queue,
                     pipe,
                     test_name="",
                     max_iter=None):  # pylint: disable=too-many-locals
    try:
        terminated = False

        def sig_term_handler(*_):
            nonlocal terminated
            terminated = True

        signal.signal(signal.SIGTERM, sig_term_handler)

        def timed_out_handler(*_):
            raise TimeoutError("studentCode timed out")

        signal.signal(signal.SIGALRM, timed_out_handler)

        def check_timed_out(func, *args):
            signal.alarm(RUNTIME_CONFIG.STUDENT_CODE_TIMELIMIT.value)
            func(*args)
            signal.alarm(0)

        signal.alarm(RUNTIME_CONFIG.STUDENT_CODE_TIMELIMIT.value)
        try:
            import studentCode
        except SyntaxError as e:
            raise RuntimeError("Student code has a syntax error: {}".format(e))
        signal.alarm(0)

        if test_name != "":
            test_name += "_"
        try:
            setup_fn = getattr(studentCode, test_name + "setup")
        except AttributeError:
            raise RuntimeError(
                "Student code failed to define '{}'".format(test_name +
                                                            "setup"))
        try:
            main_fn = getattr(studentCode, test_name + "main")
        except AttributeError:
            raise RuntimeError(
                "Student code failed to define '{}'".format(test_name +
                                                            "main"))

        ensure_is_function(test_name + "setup", setup_fn)
        ensure_is_function(test_name + "main", main_fn)
        ensure_not_overridden(studentCode, "Robot")

        # Solar Scramble specific handling
        def stub_out(funcname):
            def stub(_):
                line1 = "Failed to generate power-up code: "
                line2 = "you haven't defined {}".format(funcname)
                raise AttributeError(line1 + line2)

            return stub

        def get_or_stub_out(funcname):
            try:
                return getattr(studentCode, funcname)
            except AttributeError:
                return stub_out(funcname)

        def identity(value):
            '''
            Used only in the (hopefully) rare event that none of the other
            functions are bijections with a given domain of RFIDs
            '''
            return value

        def limit_input_to(limit):
            '''Generate a function to limit size of inputs'''
            def retval(input_val):
                while input_val > limit:
                    input_val = (input_val % limit) + (input_val // limit)
                return input_val

            return retval

        def compose_funcs(func_a, func_b):
            '''
            Composes two single-input functions together, A(B(x))
            '''
            return lambda x: func_a(func_b(x))

        next_power = get_or_stub_out("next_power")
        reverse_digits = get_or_stub_out("reverse_digits")
        smallest_prime_fact = get_or_stub_out("smallest_prime_fact")
        double_caesar_cipher = get_or_stub_out("double_caesar_cipher")
        silly_base_two = get_or_stub_out("silly_base_two")
        most_common_digit = get_or_stub_out("most_common_digit")
        valid_isbn_ten = get_or_stub_out("valid_isbn_ten")
        simd_four_square = get_or_stub_out("simd_four_square")

        func_map = [
            identity, next_power, reverse_digits,
            compose_funcs(smallest_prime_fact,
                          limit_input_to(1000000)), double_caesar_cipher,
            silly_base_two, most_common_digit, valid_isbn_ten, simd_four_square
        ]

        studentCode.Robot = Robot(state_queue, pipe, func_map)
        studentCode.Gamepad = Gamepad(state_queue, pipe)
        studentCode.Actions = Actions
        studentCode.print = studentCode.Robot._print  # pylint: disable=protected-access

        # remapping for non-class student API commands
        studentCode.get_gamepad_value = studentCode.Gamepad.get_value
        studentCode.get_robot_value = studentCode.Robot.get_value
        studentCode.set_robot_value = studentCode.Robot.set_value
        studentCode.is_robot_running = studentCode.Robot.is_running
        studentCode.run_async = studentCode.Robot.run
        studentCode.sleep_duration = studentCode.Actions.sleep

        check_timed_out(setup_fn)

        exception_cell = [None]
        clarify_coroutine_warnings(exception_cell)

        async def main_loop():
            exec_count = 0
            while not terminated and (exception_cell[0] is None) and (
                    max_iter is None or exec_count < max_iter):
                next_call = loop.time(
                ) + 1. / RUNTIME_CONFIG.STUDENT_CODE_HZ.value
                studentCode.Robot._get_all_sensors()  # pylint: disable=protected-access
                studentCode.Gamepad._get_gamepad()  # pylint: disable=protected-access
                check_timed_out(main_fn)

                # Throttle sending print statements
                if (exec_count % 5) == 0:
                    studentCode.Robot._send_prints()  # pylint: disable=protected-access

                sleep_time = max(next_call - loop.time(), 0.)
                state_queue.put([SM_COMMANDS.STUDENT_MAIN_OK, []])
                exec_count += 1
                await asyncio.sleep(sleep_time)
            if exception_cell[0] is not None:
                raise exception_cell[0]  # pylint: disable=raising-bad-type
            if not terminated:
                bad_things_queue.put(
                    BadThing(sys.exc_info(),
                             "Process Ended",
                             event=BAD_EVENTS.END_EVENT))

        loop = asyncio.get_event_loop()

        def my_exception_handler(_loop, context):
            if exception_cell[0] is None:
                exception_cell[0] = context["exception"]

        loop.set_exception_handler(my_exception_handler)
        loop.run_until_complete(main_loop())

    except TimeoutError:
        event = BAD_EVENTS.STUDENT_CODE_TIMEOUT
        bad_things_queue.put(BadThing(sys.exc_info(), event.value,
                                      event=event))
    except StudentAPIError:
        event = BAD_EVENTS.STUDENT_CODE_VALUE_ERROR
        bad_things_queue.put(BadThing(sys.exc_info(), event.value,
                                      event=event))
    except Exception as e:  # something broke in student code
        bad_things_queue.put(
            BadThing(sys.exc_info(),
                     str(e),
                     event=BAD_EVENTS.STUDENT_CODE_ERROR))