Esempio n. 1
0
    def test_finalize_notifies_for_already_stored_message_without_upload(self):
        info = LongMessageStatusInfo(LongMessageStatus.READY, b'\x01\x23\x45',
                                     123)
        data = b'foobar'

        storage = Mock()
        storage.read_status = Mock(return_value=info)
        storage.set_long_message = Mock()
        storage.get_long_message = Mock(return_value=data)

        mock_callback = Mock()

        handler = LongMessageHandler(storage)
        handler.on_message_updated(mock_callback)

        for mt in self.known_message_types:
            mock_callback.reset_mock()
            with self.subTest(mt=mt):
                handler.select_long_message_type(mt)
                handler.finalize_message()
                self.assertTrue(mock_callback.called)
                self.assertEqual(0, storage.set_long_message.call_count)
                self.assertEqual(mt,
                                 mock_callback.call_args.args[0].message_type)
                self.assertEqual('012345', mock_callback.call_args.args[0].md5)
    def test_finalize_notifies_for_already_stored_message_without_upload(self):
        storage = Mock()
        storage.read_status = Mock(return_value=LongMessageStatusInfo(
            LongMessageStatus.READY, 'new_md5', 123))
        storage.set_long_message = Mock()

        mock_callback = Mock()

        handler = LongMessageHandler(storage)
        handler.on_message_updated(mock_callback)

        for mt in self.known_message_types:
            mock_callback.reset_mock()
            with self.subTest(mt=mt):
                handler.select_long_message_type(mt)
                handler.finalize_message()
                self.assertEqual(1, mock_callback.call_count)
                self.assertEqual(0, storage.set_long_message.call_count)
    def test_finalize_notifies_about_valid_message(self, mock_hash):
        storage = Mock()
        storage.read_status = Mock(return_value=LongMessageStatusInfo(
            LongMessageStatus.READY, 'new_md5', 123))

        mock_hash.return_value = mock_hash
        mock_hash.update = Mock()
        mock_hash.hexdigest = Mock()

        mock_callback = Mock()

        handler = LongMessageHandler(storage)
        handler.on_message_updated(mock_callback)

        # message invalid
        for mt in self.known_message_types:
            mock_hash.reset_mock()

            mock_hash.hexdigest.return_value = 'invalid_md5'
            with self.subTest(mt='invalid ({})'.format(mt)):
                handler.select_long_message_type(mt)
                handler.init_transfer('new_md5')
                handler.upload_message(b'12345')
                handler.finalize_message()

                self.assertEqual(0, mock_callback.call_count)

        # message valid
        for mt in self.known_message_types:
            mock_callback.reset_mock()

            mock_hash.hexdigest.return_value = 'new_md5'
            with self.subTest(mt='valid ({})'.format(mt)):
                handler.select_long_message_type(mt)
                handler.init_transfer('new_md5')
                handler.upload_message(b'12345')
                handler.finalize_message()

                self.assertEqual(1, mock_callback.call_count)
Esempio n. 4
0
    extract_asset_longmessage(long_message_storage, writeable_assets_dir)

    with Robot() as robot:
        robot.assets.add_source(writeable_assets_dir)

        long_message_handler = LongMessageHandler(long_message_storage)
        robot_manager = RobotBLEController(
            robot, sw_version,
            RevvyBLE(device_name, serial, long_message_handler))

        lmi = LongMessageImplementation(robot_manager, long_message_storage,
                                        writeable_assets_dir, False)
        long_message_handler.on_upload_started(lmi.on_upload_started)
        long_message_handler.on_upload_progress(lmi.on_upload_progress)
        long_message_handler.on_upload_finished(lmi.on_transmission_finished)
        long_message_handler.on_message_updated(lmi.on_message_updated)

        # noinspection PyBroadException
        try:
            robot_manager.start()

            print("Press Enter to exit")
            input()
            # manual exit
            ret_val = RevvyStatusCode.OK
        except EOFError:
            robot_manager.needs_interrupting = False
            ret_val = robot_manager.wait_for_exit()
        except KeyboardInterrupt:
            # manual exit or update request
            ret_val = robot_manager.status_code
Esempio n. 5
0
def start_revvy(config: RobotConfig = None):
    current_installation = os.path.dirname(os.path.realpath(__file__))
    os.chdir(current_installation)

    # base directories
    package_data_dir = os.path.join(current_installation, 'data')

    print('Revvy run from {} ({})'.format(current_installation, __file__))

    # prepare environment

    serial = getserial()

    manifest = read_json('manifest.json')

    sound_files = {
        'alarm_clock': 'alarm_clock.mp3',
        'bell': 'bell.mp3',
        'buzzer': 'buzzer.mp3',
        'car_horn': 'car-horn.mp3',
        'cat': 'cat.mp3',
        'dog': 'dog.mp3',
        'duck': 'duck.mp3',
        'engine_revving': 'engine-revving.mp3',
        'lion': 'lion.mp3',
        'oh_no': 'oh-no.mp3',
        'robot': 'robot.mp3',
        'robot2': 'robot2.mp3',
        'siren': 'siren.mp3',
        'ta_da': 'tada.mp3',
        'uh_oh': 'uh-oh.mp3',
        'yee_haw': 'yee-haw.mp3',
    }

    def sound_path(file):
        return os.path.join(package_data_dir, 'assets', file)

    sound_paths = {key: sound_path(sound_files[key]) for key in sound_files}

    device_name = Observable("ROS")

    ble_storage_dir = os.path.join(current_installation, 'ble')
    ble_storage = FileStorage(ble_storage_dir)
    long_message_storage = LongMessageStorage(ble_storage, MemoryStorage())
    long_message_handler = LongMessageHandler(long_message_storage)

    ble = RevvyBLE(device_name, serial, long_message_handler)

    # if the robot has never been configured, set the default configuration for the simple robot
    initial_config = default_robot_config

    with RevvyTransportI2C() as transport:
        robot_control = RevvyControl(transport.bind(0x2D))

        robot = RobotManager(robot_control, ble, sound_paths,
                             manifest['version'], initial_config)

        lmi = LongMessageImplementation(robot, config is not None)
        long_message_handler.on_upload_started(lmi.on_upload_started)
        long_message_handler.on_upload_finished(lmi.on_transmission_finished)
        long_message_handler.on_message_updated(lmi.on_message_updated)

        # noinspection PyBroadException
        try:
            robot.start()

            print("Press Enter to exit")
            input()
            # manual exit
            ret_val = RevvyStatusCode.OK
        except EOFError:
            robot.needs_interrupting = False
            while not robot.exited:
                time.sleep(1)
            ret_val = robot.status_code
        except KeyboardInterrupt:
            # manual exit or update request
            ret_val = robot.status_code
        except Exception:
            print(traceback.format_exc())
            ret_val = RevvyStatusCode.ERROR
        finally:
            print('stopping')
            robot.stop()

        print('terminated.')
        return ret_val
Esempio n. 6
0
def start_revvy(config: RobotConfig = None):
    current_installation = os.path.dirname(os.path.realpath(__file__))
    os.chdir(current_installation)

    # base directories
    writeable_data_dir = os.path.join(current_installation, '..', '..', '..',
                                      'user')
    package_data_dir = os.path.join(current_installation, 'data')

    ble_storage_dir = os.path.join(writeable_data_dir, 'ble')
    data_dir = os.path.join(writeable_data_dir, 'data')

    def log_uncaught_exception(exctype, value, tb):
        log_message = 'Uncaught exception: {}\n' \
                      'Value: {}\n' \
                      'Traceback: \n\t{}\n' \
                      '\n'.format(exctype, value, "\t".join(traceback.format_tb(tb)))
        print(log_message)
        logfile = os.path.join(data_dir, 'revvy_crash.log')

        with open(logfile, 'a') as logf:
            logf.write(log_message)

    sys.excepthook = log_uncaught_exception

    # self-test
    if not check_manifest(os.path.join(current_installation, 'manifest.json')):
        print('Revvy not started because manifest is invalid')
        return RevvyStatusCode.INTEGRITY_ERROR

    print('Revvy run from {} ({})'.format(current_installation, __file__))

    # prepare environment

    serial = getserial()

    manifest = read_json('manifest.json')

    device_storage = FileStorage(data_dir)
    ble_storage = FileStorage(ble_storage_dir)

    sound_files = {
        'alarm_clock': 'alarm_clock.mp3',
        'bell': 'bell.mp3',
        'buzzer': 'buzzer.mp3',
        'car_horn': 'car-horn.mp3',
        'cat': 'cat.mp3',
        'dog': 'dog.mp3',
        'duck': 'duck.mp3',
        'engine_revving': 'engine-revving.mp3',
        'lion': 'lion.mp3',
        'oh_no': 'oh-no.mp3',
        'robot': 'robot.mp3',
        'robot2': 'robot2.mp3',
        'siren': 'siren.mp3',
        'ta_da': 'tada.mp3',
        'uh_oh': 'uh-oh.mp3',
        'yee_haw': 'yee-haw.mp3',
    }

    def sound_path(file):
        return os.path.join(package_data_dir, 'assets', file)

    sound_paths = {key: sound_path(sound_files[key]) for key in sound_files}

    dnp = DeviceNameProvider(device_storage, lambda: 'Revvy_{}'.format(serial))
    device_name = Observable(dnp.get_device_name())
    device_name.subscribe(dnp.update_device_name)

    long_message_storage = LongMessageStorage(ble_storage, MemoryStorage())
    long_message_handler = LongMessageHandler(long_message_storage)

    ble = RevvyBLE(device_name, serial, long_message_handler)

    # if the robot has never been configured, set the default configuration for the simple robot
    initial_config = config
    if config is None:
        status = long_message_storage.read_status(
            LongMessageType.CONFIGURATION_DATA)
        if status.status != LongMessageStatus.READY:
            initial_config = default_robot_config

    with RevvyTransportI2C() as transport:
        robot_control = RevvyControl(transport.bind(0x2D))
        bootloader_control = BootloaderControl(transport.bind(0x2B))

        updater = McuUpdater(robot_control, bootloader_control)
        update_manager = McuUpdateManager(
            os.path.join(package_data_dir, 'firmware'), updater)
        update_manager.update_if_necessary()

        robot = RobotManager(robot_control, ble, sound_paths,
                             manifest['version'], initial_config)

        lmi = LongMessageImplementation(robot, config is not None)
        long_message_handler.on_upload_started(lmi.on_upload_started)
        long_message_handler.on_upload_finished(lmi.on_transmission_finished)
        long_message_handler.on_message_updated(lmi.on_message_updated)

        # noinspection PyBroadException
        try:
            robot.start()

            print("Press Enter to exit")
            input()
            # manual exit
            ret_val = RevvyStatusCode.OK
        except EOFError:
            robot.needs_interrupting = False
            while not robot.exited:
                time.sleep(1)
            ret_val = robot.status_code
        except KeyboardInterrupt:
            # manual exit or update request
            ret_val = robot.status_code
        except Exception:
            print(traceback.format_exc())
            ret_val = RevvyStatusCode.ERROR
        finally:
            print('stopping')
            robot.stop()

        print('terminated.')
        return ret_val