Пример #1
0
    def test_zaxis_should_be_waited_for_buy_outputing_laser_off_signal(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        zaxis_return_values = [ 0.0,0.0, 0.25, 0.75, 1.0,1.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect

        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, mock_zaxis)
        self.controller.start()

        self.wait_for_controller()

        mock_zaxis.start.assert_called_with()
        self.assertEqual(4, mock_path_to_audio.process.call_count)
        self.assertEqual(2, mock_laser_control.set_laser_off.call_count)
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[2][0])
Пример #2
0
    def test_should_work_with_no_writer(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,None,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()
Пример #3
0
    def test_should_remember_current_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[-1.0,-1.0,0.0],2.0)
Пример #4
0
    def test_should_turn_on_laser_for_draw_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_on.call_count)
    def test_zaxis_should_be_waited_for_buy_outputing_laser_off_signal(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        zaxis_return_values = [ 0.0,0.0, 0.25, 0.75, 1.0,1.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect

        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, mock_zaxis)
        self.controller.start()

        self.wait_for_controller()

        mock_zaxis.start.assert_called_with()
        self.assertEqual(4, mock_path_to_audio.process.call_count)
        self.assertEqual(2, mock_laser_control.set_laser_off.call_count)
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[2][0])
Пример #6
0
    def test_should_output_modulate_audio_for_movement_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.assert_called_with("SomeAudio")
        mock_audio_writer.write_chunk.assert_called_with("SomeModulatedAudio")
Пример #7
0
    def test_should_record_errors_and_abort(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, len(self.controller.get_status()['errors']))
        self.assertEquals("Something Broke", self.controller.get_status()['errors'][0]['message'])
Пример #8
0
    def test_should_update_machine_status(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, self.controller.get_status()['current_layer'])
        self.assertEquals('Complete',self.controller.get_status()['status'])
Пример #9
0
    def test_should_record_errors_and_continue_when_abort_on_error_is_false(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        test_layer2 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, abort_on_error = False)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(2, len(self.controller.get_status()['errors']))
Пример #10
0
    def __init__(self, configuration_manager, printer):
        logging.info("Calibartion API Startup")
        self._configuration_manager = configuration_manager
        self._printer = printer
        self._configuration = self._configuration_manager.load(self._printer)

        self._point_generator = SinglePointGenerator()
        self._blink_generator = BlinkGenerator()
        self._alignment_generator = CalibrationLineGenerator()
        self._scale_generator = SquareGenerator(speed=1, radius=1)

        self._test_patterns = {
            'Hilbert Space Filling Curve': HilbertGenerator(),
            'Square': SquareGenerator(),
            'Circle': CircleGenerator(),
            'Spiral': SpiralGenerator(),
            'Memory Hourglass': MemoryHourglassGenerator()
        }
        self._current_generator = self._point_generator

        self._laser_control = AudioModulationLaserControl(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.modulation_on_frequency,
            self._configuration.audio.output.modulation_off_frequency,
            self._configuration.options.laser_offset)
        transformer = TuningTransformer(
            scale=self._configuration.calibration.max_deflection)
        self._path_to_audio = PathToAudio(
            self._laser_control.actual_samples_per_second, transformer,
            self._configuration.options.laser_thickness_mm)
        self._audio_writer = None
        self._controller = None
        logging.debug("Setting up audiowriter")
        self._audio_writer = AudioWriter(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.bit_depth,
        )
        self._current_generator = self._point_generator
        self._controller = Controller(
            self._laser_control,
            self._path_to_audio,
            self._audio_writer,
            self._current_generator,
        )
        self.make_pattern_fit()
        self._controller.start()
Пример #11
0
    def test_should_ignore_z_in_layer_if_z_axis_none(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,None)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(2,mock_path_to_audio.process.call_count)
        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[0.0,0.0,1.0],2.0)
Пример #12
0
    def test_if_move_command_start_and_current_pos_are_not_the_same_should_move_to_new_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralMove([0.0,0.0],[0.0,0.0],2.0), LateralMove([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.call_count = 2
        mock_path_to_audio.process.call_count = 2
        mock_laser_control.set_laser_off.assert_called_with()
        self.assertEqual(([0.0,0.0,0.0],[-1.0,-1.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])
Пример #13
0
    def test_init_should_set_call_back_on_zaxis(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_zaxis = mock_ZAxis.return_value
        Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator, mock_zaxis)

        self.assertTrue(mock_zaxis.set_call_back.called)
Пример #14
0
    def test_stop_should_close_all_processes_cleanly_while_working_on_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()
        time.sleep(0.1)

        self.controller.stop()
        time.sleep(0.1)

        mock_audio_writer.close.assert_called_with()
        
        self.wait_for_controller()
Пример #15
0
    def print_layers(self, layer_generator, dry_run=False):
        if self._configuration.serial.on:
            self._commander = SerialCommander(self._configuration.serial.port)
        else:
            self._commander = NullCommander()

        laser_control = AudioModulationLaserControl(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.modulation_on_frequency,
            self._configuration.audio.output.modulation_off_frequency,
            self._configuration.options.laser_offset)
        transformer = HomogenousTransformer(
            self._configuration.calibration.max_deflection,
            self._configuration.calibration.height,
            self._configuration.calibration.lower_points,
            self._configuration.calibration.upper_points,
        )
        path_to_audio = PathToAudio(
            laser_control.actual_samples_per_second, transformer,
            self._configuration.options.laser_thickness_mm)
        if dry_run:
            audio_writer = None
            self.zaxis = None
            zaxis_control = None
            abort_on_error = False
        else:
            audio_writer = AudioWriter(
                self._configuration.audio.output.sample_rate,
                self._configuration.audio.output.bit_depth,
            )
            self.zaxis = self._get_zaxis()
            abort_on_error = True

        self._controller = Controller(
            laser_control,
            path_to_audio,
            audio_writer,
            layer_generator,
            zaxis=self.zaxis,
            status_call_back=self._status_call_back,
            max_lead_distance=self._configuration.dripper.max_lead_distance_mm,
            abort_on_error=abort_on_error)
        self._controller.start()
Пример #16
0
    def test_should_update_layer_height(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        expected_model_height = 32.7
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 23.2
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value = Layer(expected_model_height,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()
        time.sleep(0.01)
        self.controller.stop()

        self.wait_for_controller()
        actual = self.controller.get_status()['model_height']

        self.assertEquals(expected_model_height,actual)
Пример #17
0
    def test_stop_should_close_all_processes_cleanly(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)

        self.controller.stop()

        time.sleep(0.1)

        mock_zaxis.stop.assert_called_with()
        mock_audio_writer.close.assert_called_with()
Пример #18
0
    def test_set_waiting_while_not_wating_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 1.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)
        actual = self.controller.get_status()['waiting_for_drips']
        self.controller.stop()

        self.wait_for_controller()

        self.assertFalse(actual)
Пример #19
0
    def test_should_change_layer_generator(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value

        generator1 = SinglePointGenerator([1.0,1.0])
        generator2 = SinglePointGenerator([0.0,0.0])

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,generator1)
        self.controller.start()
        time.sleep(0.1)
        pre_switch = mock_path_to_audio.process.call_args
        self.controller.change_generator(generator2)
        time.sleep(0.1)
        post_switch = mock_path_to_audio.process.call_args
        self.controller.stop()
        self.wait_for_controller()

        self.assertEquals( ([1.0,1.0,0.0],[1.0,1.0,0.0],100.0), pre_switch[0] )
        self.assertEquals( ([0.0,0.0,0.0],[0.0,0.0,0.0],100.0), post_switch[0] )
Пример #20
0
    def test_should_work_with_no_writer(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,None,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()
Пример #21
0
    def test_stop_should_stop_working_on_commands_when_generator_changed(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer1 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator1 = StubLayerGenerator([test_layer1])
        test_layer2 = Layer(1.0, [ LateralDraw([0.0,0.0],[0.0,0.0],2.0)] )
        stub_layer_generator2 = StubLayerGenerator([test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator1)
        self.controller.start()
        time.sleep(0.1)

        self.controller.change_generator(stub_layer_generator2)
        time.sleep(0.1)

        mock_path_to_audio.process.assert_called_with([0.0,0.0,1.0],[0.0,0.0,1.0],2.0)
        
        self.wait_for_controller()
Пример #22
0
    def test_if_max_lead_specifed_should_skip_layers_if_higher(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        max_lead_distance = 0.1
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        zaxis_return_values = [ 0.0, 0.0, 2.0, 2.0,2.0,2.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer2 = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer3 = Layer(2.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2, test_layer3])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,zaxis =mock_zaxis,max_lead_distance=max_lead_distance)
        self.controller.start()
        self.wait_for_controller()
        self.assertEquals(1, self.controller.get_status()['skipped_layers'])
        self.assertEquals(5, mock_audio_writer.write_chunk.call_count)
Пример #23
0
    def print_layers(self, layer_generator, dry_run = False):
        laser_control = AudioModulationLaserControl(
            self._configuration['output_sample_frequency'],
            self._configuration['on_modulation_frequency'],
            self._configuration['off_modulation_frequency']
            )
        transformer = HomogenousTransformer(self._configuration['calibration_data'], scale = self._configuration["max_deflection"])
        path_to_audio = PathToAudio(
            laser_control.actual_samples_per_second,
            transformer, 
            self._configuration['laser_thickness_mm']
            )
        if dry_run:
            audio_writer = None
            zaxis = None
            zaxis_control = None
            abort_on_error = False
        else:
            audio_writer = AudioWriter(
                self._configuration['output_sample_frequency'], 
                self._configuration['output_bit_depth'],
                )
            zaxis = DripBasedZAxis(
                drips_per_mm = self._configuration['drips_per_mm'], 
                initial_height = 0.0, 
                sample_rate = self._configuration['input_sample_frequency'],
                bit_depth = self._configuration['input_bit_depth'],
                )
            if self._configuration['use_serial_zaxis']:
                zaxis_control = SerialZAxisControl(
                                    self._configuration['serial_port'], 
                                    on_command = self._configuration['serial_on'], 
                                    off_command = self._configuration['serial_off']
                                    )
            else:
                zaxis_control = None
            abort_on_error = True

        self._controller = Controller(
            laser_control,
            path_to_audio,
            audio_writer,
            layer_generator,
            zaxis = zaxis,
            zaxis_control = zaxis_control,
            status_call_back = self._status_call_back,
            max_lead_distance = self._configuration['max_lead_distance_mm'],
            abort_on_error = abort_on_error
            )
        self._controller.start()
Пример #24
0
    def test_should_turn_on_laser_for_draw_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_on.call_count)
Пример #25
0
    def test_should_remember_current_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[-1.0,-1.0,0.0],2.0)
Пример #26
0
    def test_should_update_machine_status(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, self.controller.get_status()['current_layer'])
        self.assertEquals('Complete',self.controller.get_status()['status'])
Пример #27
0
    def test_should_record_errors_and_abort(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, len(self.controller.get_status()['errors']))
        self.assertEquals("Something Broke", self.controller.get_status()['errors'][0]['message'])
Пример #28
0
    def test_should_output_modulate_audio_for_movement_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.assert_called_with("SomeAudio")
        mock_audio_writer.write_chunk.assert_called_with("SomeModulatedAudio")
Пример #29
0
    def test_should_record_errors_and_continue_when_abort_on_error_is_false(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        test_layer2 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, abort_on_error = False)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(2, len(self.controller.get_status()['errors']))
    def print_layers(self, layer_generator, dry_run = False):
        if self._configuration.serial.on:
            self._commander = SerialCommander( self._configuration.serial.port )
        else:
            self._commander = NullCommander()

        laser_control = AudioModulationLaserControl(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.modulation_on_frequency,
            self._configuration.audio.output.modulation_off_frequency,
            self._configuration.options.laser_offset
            )
        transformer = HomogenousTransformer(
            self._configuration.calibration.max_deflection,
            self._configuration.calibration.height,
            self._configuration.calibration.lower_points,
            self._configuration.calibration.upper_points,
            )
        path_to_audio = PathToAudio(
            laser_control.actual_samples_per_second,
            transformer, 
            self._configuration.options.laser_thickness_mm
            )
        if dry_run:
            audio_writer = None
            self.zaxis = None
            zaxis_control = None
            abort_on_error = False
        else:
            audio_writer = AudioWriter(
                self._configuration.audio.output.sample_rate, 
                self._configuration.audio.output.bit_depth,
                )
            self.zaxis = self._get_zaxis()
            abort_on_error = True

        self._controller = Controller(
            laser_control,
            path_to_audio,
            audio_writer,
            layer_generator,
            zaxis = self.zaxis,
            status_call_back = self._status_call_back,
            max_lead_distance = self._configuration.dripper.max_lead_distance_mm,
            abort_on_error = abort_on_error
            )
        self._controller.start()
Пример #31
0
    def test_should_ignore_z_in_layer_if_z_axis_none(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,None)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(2,mock_path_to_audio.process.call_count)
        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[0.0,0.0,1.0],2.0)
Пример #32
0
    def test_if_move_command_start_and_current_pos_are_not_the_same_should_move_to_new_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralMove([0.0,0.0],[0.0,0.0],2.0), LateralMove([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.call_count = 2
        mock_path_to_audio.process.call_count = 2
        mock_laser_control.set_laser_off.assert_called_with()
        self.assertEqual(([0.0,0.0,0.0],[-1.0,-1.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])
Пример #33
0
    def __init__(self, configuration_manager, printer):
        logging.info("Calibartion API Startup")
        self._configuration_manager = configuration_manager
        self._printer = printer
        self._configuration = self._configuration_manager.load(self._printer)

        self._point_generator = SinglePointGenerator()
        self._alignment_generator = CalibrationLineGenerator()

        self._test_patterns = { 
            'Hilbert Space Filling Curve' : HilbertGenerator(),
            'Square' : SquareGenerator(),
            'Circle' : CircleGenerator(),
            'Spiral' : SpiralGenerator(),
            }
        self._current_generator = self._point_generator

        self._laser_control = AudioModulationLaserControl(
            self._configuration['output_sample_frequency'],
            self._configuration['on_modulation_frequency'],
            self._configuration['off_modulation_frequency']
            )
        transformer = TuningTransformer(scale = self._configuration["max_deflection"])
        self._path_to_audio= PathToAudio(
            self._laser_control.actual_samples_per_second,
            transformer,
            self._configuration["laser_thickness_mm"]
            )
        self._audio_writer = None
        self._controller = None
        logging.debug("Setting up audiowriter")
        self._audio_writer = AudioWriter(
            self._configuration['output_sample_frequency'], 
            self._configuration['output_bit_depth'],
            )
        self._current_generator = self._point_generator
        self._controller = Controller(
            self._laser_control,
            self._path_to_audio,
            self._audio_writer,
            self._current_generator,
            )
        self.make_pattern_fit()
        self._controller.start()
Пример #34
0
    def test_stop_should_close_all_processes_cleanly_while_working_on_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()
        time.sleep(0.1)

        self.controller.stop()
        time.sleep(0.1)

        mock_audio_writer.close.assert_called_with()
        
        self.wait_for_controller()
Пример #35
0
    def test_should_change_layer_generator(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value

        generator1 = SinglePointGenerator([1.0,1.0])
        generator2 = SinglePointGenerator([0.0,0.0])

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,generator1)
        self.controller.start()
        time.sleep(0.1)
        pre_switch = mock_path_to_audio.process.call_args
        self.controller.change_generator(generator2)
        time.sleep(0.1)
        post_switch = mock_path_to_audio.process.call_args
        self.controller.stop()
        self.wait_for_controller()

        self.assertEquals( ([1.0,1.0,0.0],[1.0,1.0,0.0],100.0), pre_switch[0] )
        self.assertEquals( ([0.0,0.0,0.0],[0.0,0.0,0.0],100.0), post_switch[0] )
Пример #36
0
    def test_set_waiting_while_not_wating_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 1.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)
        actual = self.controller.get_status()['waiting_for_drips']
        self.controller.stop()

        self.wait_for_controller()

        self.assertFalse(actual)
Пример #37
0
    def test_should_update_layer_height(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        expected_model_height = 32.7
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 23.2
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value = Layer(expected_model_height,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()
        time.sleep(0.01)
        self.controller.stop()

        self.wait_for_controller()
        actual = self.controller.get_status()['model_height']

        self.assertEquals(expected_model_height,actual)
Пример #38
0
    def test_stop_should_close_all_processes_cleanly(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)

        self.controller.stop()

        time.sleep(0.1)

        mock_zaxis.stop.assert_called_with()
        mock_audio_writer.close.assert_called_with()
Пример #39
0
    def test_stop_should_stop_working_on_commands_when_generator_changed(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer1 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator1 = StubLayerGenerator([test_layer1])
        test_layer2 = Layer(1.0, [ LateralDraw([0.0,0.0],[0.0,0.0],2.0)] )
        stub_layer_generator2 = StubLayerGenerator([test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator1)
        self.controller.start()
        time.sleep(0.1)

        self.controller.change_generator(stub_layer_generator2)
        time.sleep(0.1)

        mock_path_to_audio.process.assert_called_with([0.0,0.0,1.0],[0.0,0.0,1.0],2.0)
        
        self.wait_for_controller()
Пример #40
0
    def test_if_max_lead_specifed_should_skip_layers_if_higher(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        max_lead_distance = 0.1
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        zaxis_return_values = [ 0.0, 0.0, 2.0, 2.0,2.0,2.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer2 = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer3 = Layer(2.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2, test_layer3])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,zaxis =mock_zaxis,max_lead_distance=max_lead_distance)
        self.controller.start()
        self.wait_for_controller()
        self.assertEquals(1, self.controller.get_status()['skipped_layers'])
        self.assertEquals(5, mock_audio_writer.write_chunk.call_count)
Пример #41
0
    def test_if_zaxis_control_specifed_should_call_start_and_stop_correctly(self, mock_ZAxisControl, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_zaxis_control = mock_ZAxisControl.return_value
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        zaxis_return_values = [ 0.0, 0.0, 2.0, 2.0,2.0,2.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer2 = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer3 = Layer(2.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2, test_layer3])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,zaxis = mock_zaxis, zaxis_control = mock_zaxis_control, max_lead_distance = 0)
        self.controller.start()
        self.wait_for_controller()
        expected_calls = [ call.move_up(), call.stop(), call.stop(), call.close()]
        actual = [ c for c in mock_zaxis_control.mock_calls if c != call.__nonzero__() ]
        self.assertEquals(expected_calls, actual)
Пример #42
0
class CalibrationAPI(object):
    def __init__(self, configuration_manager, printer):
        logging.info("Calibartion API Startup")
        self._configuration_manager = configuration_manager
        self._printer = printer
        self._configuration = self._configuration_manager.load(self._printer)

        self._point_generator = SinglePointGenerator()
        self._blink_generator = BlinkGenerator()
        self._alignment_generator = CalibrationLineGenerator()
        self._scale_generator = SquareGenerator(speed=1, radius=1)

        self._test_patterns = {
            'Hilbert Space Filling Curve': HilbertGenerator(),
            'Square': SquareGenerator(),
            'Circle': CircleGenerator(),
            'Spiral': SpiralGenerator(),
            'Memory Hourglass': MemoryHourglassGenerator()
        }
        self._current_generator = self._point_generator

        self._laser_control = AudioModulationLaserControl(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.modulation_on_frequency,
            self._configuration.audio.output.modulation_off_frequency,
            self._configuration.options.laser_offset)
        transformer = TuningTransformer(
            scale=self._configuration.calibration.max_deflection)
        self._path_to_audio = PathToAudio(
            self._laser_control.actual_samples_per_second, transformer,
            self._configuration.options.laser_thickness_mm)
        self._audio_writer = None
        self._controller = None
        logging.debug("Setting up audiowriter")
        self._audio_writer = AudioWriter(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.bit_depth,
        )
        self._current_generator = self._point_generator
        self._controller = Controller(
            self._laser_control,
            self._path_to_audio,
            self._audio_writer,
            self._current_generator,
        )
        self.make_pattern_fit()
        self._controller.start()

    '''Used to show a single point with no calibration applied'''

    def show_point(self, xyz=[0.5, 0.5, 0.5]):
        x, y, z = xyz
        self._point_generator.xy = [x, y]
        if (self._current_generator != self._point_generator):
            self._unapply_calibration()
            self._update_generator(self._point_generator)

    '''Used to show a blinking point with no calibration applied used for aligning on and off laser posisition'''

    def show_blink(self, xyz=[0.5, 0.5, 0.0]):
        x, y, z = xyz
        self._blink_generator.xy = [x, y]
        if (self._current_generator != self._blink_generator):
            self._unapply_calibration()
            self._update_generator(self._blink_generator)

    '''Used to show a single line on one axis used to line up calibration grid'''

    def show_line(self):
        self._unapply_calibration()
        self._update_generator(self._alignment_generator)

    def get_max_deflection(self):
        return self._configuration.calibration.max_deflection

    def set_max_deflection(self, deflection):
        self._configuration.calibration.max_deflection = deflection
        self._unapply_calibration()
        self._save()

    '''Allows user so force the laser on'''

    def set_laser_off_override(self, state):
        self._controller.laser_off_override = state

    '''Gets the currently configured offset for laser on and off'''

    def get_laser_offset(self):
        return self._configuration.options.laser_offset

    '''Sets the currently configured offset for laser on and off'''

    def set_laser_offset(self, laser_offset):
        self._configuration.options.laser_offset = laser_offset
        self._laser_control.set_offset(laser_offset)
        self._save()

    '''Used to show a test pattern with calibration applied'''

    def show_test_pattern(self, pattern):
        if pattern in self._test_patterns.keys():
            self._apply_calibration()
            self._update_generator(self._test_patterns[pattern])
        else:
            logging.error('Pattern: %s does not exist' % pattern)
            raise Exception('Pattern: %s does not exist' % pattern)

    '''Changes the speed at which the test pattern is drawn in mm/sec'''

    def set_test_pattern_speed(self, speed):
        [pattern.set_speed(speed) for pattern in self._test_patterns.values()]

    '''Shows the scale square'''

    def show_scale(self):
        self._unapply_calibration()
        self._update_generator(self._scale_generator)

    '''returns a list of test patterns'''

    def get_test_patterns(self):
        return self._test_patterns.keys()

    '''Returns the current calibration for the printer'''

    def current_calibration(self):
        return self._configuration.calibration

    '''Saves the suppliled calibration'''

    def save_points(self, height, lower_points, upper_points):
        self._configuration.calibration.height = height
        self._configuration.calibration.lower_points = lower_points
        self._configuration.calibration.upper_points = upper_points
        self._save()

    def _save(self):
        self._configuration_manager.save(self._configuration)
        self.make_pattern_fit()  #TODO make this better.

    #deprecated
    def make_pattern_fit(self):
        for pattern in self._test_patterns.values():
            pattern.set_radius(self.get_largest_object_radius())

    '''Must be called before shutting down applications'''

    def stop(self):
        self._controller.stop()

    def _update_generator(self, generator):
        self._current_generator = generator
        self._controller.change_generator(self._current_generator)

    def _apply_calibration(self):
        self._path_to_audio.set_transformer(
            HomogenousTransformer(
                scale=self._configuration.calibration.max_deflection,
                upper_height=self._configuration.calibration.height,
                lower_points=self._configuration.calibration.lower_points,
                upper_points=self._configuration.calibration.upper_points))

    def _unapply_calibration(self):
        self._path_to_audio.set_transformer(
            TuningTransformer(
                scale=self._configuration.calibration.max_deflection))

    def _validate_points(self, points):
        if (len(points) != 4):
            return False
        return True

    '''Based on current calibrations_gets_maximum_size_of_object at the base layer'''

    def get_largest_object_radius(self):
        lowest = None
        for (x, y) in self._configuration.calibration.lower_points.values():
            if not lowest or abs(x) < lowest:
                lowest = abs(x)
            if abs(y) < lowest:
                lowest = abs(y)
        return lowest

    def stop(self):
        self._controller.stop()
Пример #43
0
class CalibrationAPI(object):
    def __init__(self, configuration_manager, printer):
        logging.info("Calibartion API Startup")
        self._configuration_manager = configuration_manager
        self._printer = printer
        self._configuration = self._configuration_manager.load(self._printer)

        self._point_generator = SinglePointGenerator()
        self._alignment_generator = CalibrationLineGenerator()

        self._test_patterns = { 
            'Hilbert Space Filling Curve' : HilbertGenerator(),
            'Square' : SquareGenerator(),
            'Circle' : CircleGenerator(),
            'Spiral' : SpiralGenerator(),
            }
        self._current_generator = self._point_generator

        self._laser_control = AudioModulationLaserControl(
            self._configuration['output_sample_frequency'],
            self._configuration['on_modulation_frequency'],
            self._configuration['off_modulation_frequency']
            )
        transformer = TuningTransformer(scale = self._configuration["max_deflection"])
        self._path_to_audio= PathToAudio(
            self._laser_control.actual_samples_per_second,
            transformer,
            self._configuration["laser_thickness_mm"]
            )
        self._audio_writer = None
        self._controller = None
        logging.debug("Setting up audiowriter")
        self._audio_writer = AudioWriter(
            self._configuration['output_sample_frequency'], 
            self._configuration['output_bit_depth'],
            )
        self._current_generator = self._point_generator
        self._controller = Controller(
            self._laser_control,
            self._path_to_audio,
            self._audio_writer,
            self._current_generator,
            )
        self.make_pattern_fit()
        self._controller.start()

    '''Used to show a single point with no calibration applied'''
    def show_point(self,xyz = [0.5,0.5,0.5]):
        x,y,z = xyz
        self._point_generator.xy = [x,y]
        if (self._current_generator != self._point_generator):
            self._unapply_calibration()
            self._update_generator(self._point_generator)

    '''Used to show a single line on one axis used to line up calibration grid'''
    def show_line(self):
        self._unapply_calibration()
        self._update_generator(self._alignment_generator)

    def get_max_deflection(self):
        return self._configuration['max_deflection']

    def set_max_deflection(self, deflection):
        self._configuration['max_deflection'] = deflection
        self._unapply_calibration()
        self._configuration_manager.save(self._configuration)

    '''Used to show a test pattern with calibration applied'''
    def show_test_pattern(self,pattern):
        if pattern in self._test_patterns.keys():
            self._apply_calibration()
            self._update_generator(self._test_patterns[pattern])
        else:
            logging.error('Pattern: %s does not exist' % pattern)
            raise Exception('Pattern: %s does not exist' % pattern)

    '''Shows the scale square'''
    def show_scale(self):
        self._unapply_calibration()
        self._update_generator(self._test_patterns['Square'])

    '''returns a list of test patterns'''
    def get_test_patterns(self):
        return self._test_patterns.keys()

    '''Returns the current calibration for the printer'''
    def current_calibration(self):
        return self._configuration['calibration_data']

    '''Saves the suppliled calibration'''
    def save(self, calibration):
        if not self.validate(calibration):
            raise Exception('Bad Calibration %s ' % calibration)
        self._configuration['calibration_data'] = calibration
        logging.debug("Saving calibration: %s" % calibration)
        self._configuration_manager.save(self._configuration)
        self.make_pattern_fit() #TODO make this better.

    #deprecated
    def make_pattern_fit(self):
        for pattern in self._test_patterns.values():
            pattern.set_radius(self.get_largest_object_radius())



    '''Validates a calibration'''
    def validate(self, calibration):
        if not 'height' in calibration:
            return False
        if not 'upper_points' in calibration:
            return False
        if not 'lower_points' in calibration:
            return False
        if (type(calibration['height']) != types.FloatType):
            return False
        if (calibration['height'] <= 0.0):
            return False
        if not self._validate_points(calibration['upper_points']):
            return False
        if not self._validate_points(calibration['lower_points']):
            return False
        return True

    '''Must be called before shutting down applications'''
    def stop(self):
        self._controller.stop()

    def _update_generator(self, generator):
        self._current_generator = generator
        self._controller.change_generator(self._current_generator)

    def _apply_calibration(self):
        self._path_to_audio.set_transformer(HomogenousTransformer(self._configuration['calibration_data'], scale = self._configuration["max_deflection"]))

    def _unapply_calibration(self):
        self._path_to_audio.set_transformer(TuningTransformer(scale = self._configuration["max_deflection"]))
    
    def _validate_points(self,points):
        if (len(points) != 4):
            return False
        return True

    '''Based on current calibrations_gets_maximum_size_of_object at the base layer'''
    def get_largest_object_radius(self):
        lowest = None
        for (x,y) in self._configuration['calibration_data']['lower_points'].values():
            if not lowest or abs(x) < lowest:
                lowest = abs(x)
            if abs(y) < lowest:
                lowest = abs(y)
        return lowest

    def stop(self):
            self._controller.stop()
Пример #44
0
class PrintAPI(object):
    def __init__(self, configuration, status_call_back = None):
        logging.info("Print API Startup")
        self._configuration = configuration
        self._controller = None
        self._status_call_back = status_call_back

    def print_gcode(self, file_like_object, print_sub_layers = True, dry_run = False):
        gcode_reader = GCodeReader(file_like_object)
        gcode_layer_generator = gcode_reader.get_layers()
        if print_sub_layers:
            layer_generator = SubLayerGenerator(gcode_layer_generator, self._configuration['sublayer_height_mm'])
        else:
            layer_generator = gcode_layer_generator
        self.print_layers(layer_generator, dry_run)

    def print_layers(self, layer_generator, dry_run = False):
        laser_control = AudioModulationLaserControl(
            self._configuration['output_sample_frequency'],
            self._configuration['on_modulation_frequency'],
            self._configuration['off_modulation_frequency']
            )
        transformer = HomogenousTransformer(self._configuration['calibration_data'], scale = self._configuration["max_deflection"])
        path_to_audio = PathToAudio(
            laser_control.actual_samples_per_second,
            transformer, 
            self._configuration['laser_thickness_mm']
            )
        if dry_run:
            audio_writer = None
            zaxis = None
            zaxis_control = None
            abort_on_error = False
        else:
            audio_writer = AudioWriter(
                self._configuration['output_sample_frequency'], 
                self._configuration['output_bit_depth'],
                )
            zaxis = DripBasedZAxis(
                drips_per_mm = self._configuration['drips_per_mm'], 
                initial_height = 0.0, 
                sample_rate = self._configuration['input_sample_frequency'],
                bit_depth = self._configuration['input_bit_depth'],
                )
            if self._configuration['use_serial_zaxis']:
                zaxis_control = SerialZAxisControl(
                                    self._configuration['serial_port'], 
                                    on_command = self._configuration['serial_on'], 
                                    off_command = self._configuration['serial_off']
                                    )
            else:
                zaxis_control = None
            abort_on_error = True

        self._controller = Controller(
            laser_control,
            path_to_audio,
            audio_writer,
            layer_generator,
            zaxis = zaxis,
            zaxis_control = zaxis_control,
            status_call_back = self._status_call_back,
            max_lead_distance = self._configuration['max_lead_distance_mm'],
            abort_on_error = abort_on_error
            )
        self._controller.start()


    def get_status(self):
        return self._controller.get_status()

    def verify_gcode(self, g_code_file_like_object):
        self.print_gcode(g_code_file_like_object, dry_run = True)

    def stop(self):
        if self._controller:
            self._controller.stop()
        else:
            logging.warning('Stopped before printing')
Пример #45
0
class PrintAPI(object):
    def __init__(self, configuration, status_call_back=None):
        logging.info("Print API Startup")
        self._configuration = configuration
        self._controller = None
        self._status_call_back = status_call_back

    def print_gcode(self,
                    file_like_object,
                    print_sub_layers=True,
                    dry_run=False):
        gcode_reader = GCodeReader(file_like_object)
        gcode_layer_generator = gcode_reader.get_layers()
        if print_sub_layers:
            layer_generator = SubLayerGenerator(
                gcode_layer_generator,
                self._configuration.options.sublayer_height_mm)
        else:
            layer_generator = gcode_layer_generator
        self.print_layers(layer_generator, dry_run)

    def _get_zaxis(self):
        if self._configuration.dripper.dripper_type == 'audio':
            return AudioDripZAxis(self._configuration.dripper.drips_per_mm,
                                  self._configuration.audio.input.sample_rate,
                                  self._configuration.audio.input.bit_depth,
                                  self._commander,
                                  self._configuration.serial.on_command,
                                  self._configuration.serial.off_command)
        elif self._configuration.dripper.dripper_type == 'emulated':
            return TimedDripZAxis(self._configuration.dripper.drips_per_mm,
                                  drips_per_second=self._configuration.dripper.
                                  emulated_drips_per_second)

    def print_layers(self, layer_generator, dry_run=False):
        if self._configuration.serial.on:
            self._commander = SerialCommander(self._configuration.serial.port)
        else:
            self._commander = NullCommander()

        laser_control = AudioModulationLaserControl(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.modulation_on_frequency,
            self._configuration.audio.output.modulation_off_frequency,
            self._configuration.options.laser_offset)
        transformer = HomogenousTransformer(
            self._configuration.calibration.max_deflection,
            self._configuration.calibration.height,
            self._configuration.calibration.lower_points,
            self._configuration.calibration.upper_points,
        )
        path_to_audio = PathToAudio(
            laser_control.actual_samples_per_second, transformer,
            self._configuration.options.laser_thickness_mm)
        if dry_run:
            audio_writer = None
            self.zaxis = None
            zaxis_control = None
            abort_on_error = False
        else:
            audio_writer = AudioWriter(
                self._configuration.audio.output.sample_rate,
                self._configuration.audio.output.bit_depth,
            )
            self.zaxis = self._get_zaxis()
            abort_on_error = True

        self._controller = Controller(
            laser_control,
            path_to_audio,
            audio_writer,
            layer_generator,
            zaxis=self.zaxis,
            status_call_back=self._status_call_back,
            max_lead_distance=self._configuration.dripper.max_lead_distance_mm,
            abort_on_error=abort_on_error)
        self._controller.start()

    def get_status(self):
        return self._controller.get_status()

    def can_set_drips_per_second(self):
        if getattr(self.zaxis, 'set_drips_per_second', False):
            return True
        else:
            return False

    def set_drips_per_second(self, drips_per_second):
        if getattr(self.zaxis, 'set_drips_per_second', False):
            self.zaxis.set_drips_per_second(drips_per_second)
        else:
            logging.error('Cannot change drips per second on %s' %
                          type(self.zaxis))
            raise Exception('Cannot change drips per second on %s' %
                            type(self.zaxis))

    def get_drips_per_second(self):
        if getattr(self.zaxis, 'get_drips_per_second'):
            return self.zaxis.get_drips_per_second()
        else:
            logging.warning("Drips per second requested but does not exist")
            return 0.0

    def verify_gcode(self, g_code_file_like_object):
        self.print_gcode(g_code_file_like_object, dry_run=True)

    def stop(self):
        if self._controller:
            self._controller.stop()
        else:
            logging.warning('Stopped before printing')
Пример #46
0
class ControllerTests(unittest.TestCase):
    controller = None

    def wait_for_controller(self):
        while self.controller.starting or self.controller.running:
            time.sleep(0.01)

    def tearDown(self):
        if self.controller and self.controller.is_alive():
            self.controller.stop()


    def test_should_turn_on_laser_for_draw_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_on.call_count)

    def test_should_work_with_no_writer(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,None,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

    def test_should_turn_off_laser_for_move_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralMove([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
                
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_off.call_count)
        self.assertEqual(0,mock_laser_control.set_laser_on.call_count)

    def test_should_turn_off_laser_for_draw_commands_when_forced_off(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.laser_off_override = True
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_off.call_count)
        self.assertEqual(0,mock_laser_control.set_laser_on.call_count)

    def test_should_output_modulate_audio_for_movement_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.assert_called_with("SomeAudio")
        mock_audio_writer.write_chunk.assert_called_with("SomeModulatedAudio")

    def test_should_call_path_to_audio_with_xyz(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_path_to_audio.process.assert_called_with([0.0,0.0,0.0],[2.0,2.0,0.0],2.0)

    def test_should_remember_current_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[-1.0,-1.0,0.0],2.0)

    def test_if_max_lead_specifed_should_skip_layers_if_higher(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        max_lead_distance = 0.1
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        zaxis_return_values = [ 0.0, 0.0, 2.0, 2.0,2.0,2.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer2 = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer3 = Layer(2.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2, test_layer3])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,zaxis =mock_zaxis,max_lead_distance=max_lead_distance)
        self.controller.start()
        self.wait_for_controller()
        self.assertEquals(1, self.controller.get_status()['skipped_layers'])
        self.assertEquals(5, mock_audio_writer.write_chunk.call_count)

    def test_if_draw_command_start_and_current_pos_are_not_the_same_should_move_to_new_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ 
            LateralDraw([0.0,0.0],[0.0,0.0],2.0), 
            LateralDraw([2.0,2.0],[-1.0,-1.0],2.0)
             ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.call_count = 3
        mock_path_to_audio.process.call_count = 3
        mock_laser_control.set_laser_off.assert_called_with()
        self.assertEqual(([0.0,0.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])

    def test_if_move_command_start_and_current_pos_are_not_the_same_should_move_to_new_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralMove([0.0,0.0],[0.0,0.0],2.0), LateralMove([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.call_count = 2
        mock_path_to_audio.process.call_count = 2
        mock_laser_control.set_laser_off.assert_called_with()
        self.assertEqual(([0.0,0.0,0.0],[-1.0,-1.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])

    def test_should_ignore_z_in_layer_if_z_axis_none(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,None)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(2,mock_path_to_audio.process.call_count)
        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[0.0,0.0,1.0],2.0)

    def test_zaxis_should_be_waited_for_buy_outputing_laser_off_signal(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        zaxis_return_values = [ 0.0,0.0, 0.25, 0.75, 1.0,1.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect

        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, mock_zaxis)
        self.controller.start()

        self.wait_for_controller()

        mock_zaxis.start.assert_called_with()
        self.assertEqual(4, mock_path_to_audio.process.call_count)
        self.assertEqual(2, mock_laser_control.set_laser_off.call_count)
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[2][0])

    def test_stop_should_close_all_processes_cleanly(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)

        self.controller.stop()

        time.sleep(0.1)

        mock_zaxis.stop.assert_called_with()
        mock_audio_writer.close.assert_called_with()

    def test_stop_should_close_all_processes_cleanly_while_waiting_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 0.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =   Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)

        self.controller.stop()

        self.wait_for_controller()

        mock_zaxis.stop.assert_called_with()
        mock_audio_writer.close.assert_called_with()

    def test_stop_should_close_all_processes_cleanly_while_working_on_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()
        time.sleep(0.1)

        self.controller.stop()
        time.sleep(0.1)

        mock_audio_writer.close.assert_called_with()
        
        self.wait_for_controller()


    def test_set_waiting_while_wating_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 0.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.01)
        actual = self.controller.get_status()['waiting_for_drips']
        self.controller.stop()

        self.wait_for_controller()

        self.assertTrue(actual)

    def test_should_update_layer_height(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        expected_model_height = 32.7
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 23.2
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value = Layer(expected_model_height,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()
        time.sleep(0.01)
        self.controller.stop()

        self.wait_for_controller()
        actual = self.controller.get_status()['model_height']

        self.assertEquals(expected_model_height,actual)

    def test_set_waiting_while_not_wating_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 1.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)
        actual = self.controller.get_status()['waiting_for_drips']
        self.controller.stop()

        self.wait_for_controller()

        self.assertFalse(actual)
        
    def test_should_update_machine_status(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, self.controller.get_status()['current_layer'])
        self.assertEquals('Complete',self.controller.get_status()['status'])

    def test_should_record_errors_and_abort(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, len(self.controller.get_status()['errors']))
        self.assertEquals("Something Broke", self.controller.get_status()['errors'][0]['message'])

    def test_should_record_errors_and_continue_when_abort_on_error_is_false(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        test_layer2 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, abort_on_error = False)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(2, len(self.controller.get_status()['errors']))

    def test_should_change_layer_generator(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value

        generator1 = SinglePointGenerator([1.0,1.0])
        generator2 = SinglePointGenerator([0.0,0.0])

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,generator1)
        self.controller.start()
        time.sleep(0.1)
        pre_switch = mock_path_to_audio.process.call_args
        self.controller.change_generator(generator2)
        time.sleep(0.1)
        post_switch = mock_path_to_audio.process.call_args
        self.controller.stop()
        self.wait_for_controller()

        self.assertEquals( ([1.0,1.0,0.0],[1.0,1.0,0.0],100.0), pre_switch[0] )
        self.assertEquals( ([0.0,0.0,0.0],[0.0,0.0,0.0],100.0), post_switch[0] )

    def test_stop_should_stop_working_on_commands_when_generator_changed(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer1 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator1 = StubLayerGenerator([test_layer1])
        test_layer2 = Layer(1.0, [ LateralDraw([0.0,0.0],[0.0,0.0],2.0)] )
        stub_layer_generator2 = StubLayerGenerator([test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator1)
        self.controller.start()
        time.sleep(0.1)

        self.controller.change_generator(stub_layer_generator2)
        time.sleep(0.1)

        mock_path_to_audio.process.assert_called_with([0.0,0.0,1.0],[0.0,0.0,1.0],2.0)
        
        self.wait_for_controller()


    def test_init_should_set_call_back_on_zaxis(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_zaxis = mock_ZAxis.return_value
        Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator, mock_zaxis)

        self.assertTrue(mock_zaxis.set_call_back.called)
class PrintAPI(object):
    def __init__(self, configuration, status_call_back = None):
        logging.info("Print API Startup")
        self._configuration = configuration
        self._controller = None
        self._status_call_back = status_call_back

    def print_gcode(self, file_like_object, print_sub_layers = True, dry_run = False):
        gcode_reader = GCodeReader(file_like_object)
        gcode_layer_generator = gcode_reader.get_layers()
        if print_sub_layers:
            layer_generator = SubLayerGenerator(gcode_layer_generator, self._configuration.options.sublayer_height_mm)
        else:
            layer_generator = gcode_layer_generator
        self.print_layers(layer_generator, dry_run)

    def _get_zaxis(self):
        if self._configuration.dripper.dripper_type == 'audio':
            return AudioDripZAxis(
                self._configuration.dripper.drips_per_mm, 
                self._configuration.audio.input.sample_rate,
                self._configuration.audio.input.bit_depth,
                self._commander,
                self._configuration.serial.on_command, 
                self._configuration.serial.off_command
                )
        elif self._configuration.dripper.dripper_type == 'emulated':
            return TimedDripZAxis(
                self._configuration.dripper.drips_per_mm, 
                drips_per_second = self._configuration.dripper.emulated_drips_per_second
                )

    def print_layers(self, layer_generator, dry_run = False):
        if self._configuration.serial.on:
            self._commander = SerialCommander( self._configuration.serial.port )
        else:
            self._commander = NullCommander()

        laser_control = AudioModulationLaserControl(
            self._configuration.audio.output.sample_rate,
            self._configuration.audio.output.modulation_on_frequency,
            self._configuration.audio.output.modulation_off_frequency,
            self._configuration.options.laser_offset
            )
        transformer = HomogenousTransformer(
            self._configuration.calibration.max_deflection,
            self._configuration.calibration.height,
            self._configuration.calibration.lower_points,
            self._configuration.calibration.upper_points,
            )
        path_to_audio = PathToAudio(
            laser_control.actual_samples_per_second,
            transformer, 
            self._configuration.options.laser_thickness_mm
            )
        if dry_run:
            audio_writer = None
            self.zaxis = None
            zaxis_control = None
            abort_on_error = False
        else:
            audio_writer = AudioWriter(
                self._configuration.audio.output.sample_rate, 
                self._configuration.audio.output.bit_depth,
                )
            self.zaxis = self._get_zaxis()
            abort_on_error = True

        self._controller = Controller(
            laser_control,
            path_to_audio,
            audio_writer,
            layer_generator,
            zaxis = self.zaxis,
            status_call_back = self._status_call_back,
            max_lead_distance = self._configuration.dripper.max_lead_distance_mm,
            abort_on_error = abort_on_error
            )
        self._controller.start()

    def get_status(self):
        return self._controller.get_status()

    def can_set_drips_per_second(self):
        if getattr(self.zaxis, 'set_drips_per_second', False):
            return True
        else:
            return False

    def set_drips_per_second(self, drips_per_second):
        if getattr(self.zaxis, 'set_drips_per_second', False):
            self.zaxis.set_drips_per_second(drips_per_second)
        else:
            logging.error('Cannot change drips per second on %s' % type(self.zaxis))
            raise Exception('Cannot change drips per second on %s' % type(self.zaxis))

    def get_drips_per_second(self):
        if getattr(self.zaxis, 'get_drips_per_second'):
            return self.zaxis.get_drips_per_second()
        else:
            logging.warning("Drips per second requested but does not exist")
            return 0.0

    def verify_gcode(self, g_code_file_like_object):
        self.print_gcode(g_code_file_like_object, dry_run = True)

    def stop(self):
        if self._controller:
            self._controller.stop()
        else:
            logging.warning('Stopped before printing')
Пример #48
0
class ControllerTests(unittest.TestCase):
    controller = None

    def wait_for_controller(self):
        while self.controller.starting or self.controller.running:
            time.sleep(0.01)

    def tearDown(self):
        if self.controller and self.controller.is_alive():
            self.controller.stop()


    def test_should_turn_on_laser_for_draw_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_on.call_count)

    def test_should_work_with_no_writer(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,None,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()


    def test_should_turn_off_laser_for_move_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralMove([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
                
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(1,mock_laser_control.set_laser_off.call_count)
        self.assertEqual(0,mock_laser_control.set_laser_on.call_count)

    def test_should_output_modulate_audio_for_movement_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.assert_called_with("SomeAudio")
        mock_audio_writer.write_chunk.assert_called_with("SomeModulatedAudio")

    def test_should_call_path_to_audio_with_xyz(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_path_to_audio.process.assert_called_with([0.0,0.0,0.0],[2.0,2.0,0.0],2.0)

    def test_should_remember_current_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[-1.0,-1.0,0.0],2.0)

    def test_if_max_lead_specifed_should_skip_layers_if_higher(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        max_lead_distance = 0.1
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        zaxis_return_values = [ 0.0, 0.0, 2.0, 2.0,2.0,2.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer2 = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer3 = Layer(2.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2, test_layer3])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,zaxis =mock_zaxis,max_lead_distance=max_lead_distance)
        self.controller.start()
        self.wait_for_controller()
        self.assertEquals(1, self.controller.get_status()['skipped_layers'])
        self.assertEquals(5, mock_audio_writer.write_chunk.call_count)

    @patch('infrastructure.zaxis_control.ZAxisControl')
    def test_if_zaxis_control_specifed_should_call_start_and_stop_correctly(self, mock_ZAxisControl, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_zaxis_control = mock_ZAxisControl.return_value
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        zaxis_return_values = [ 0.0, 0.0, 2.0, 2.0,2.0,2.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer2 = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        test_layer3 = Layer(2.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0), LateralDraw([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2, test_layer3])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,zaxis = mock_zaxis, zaxis_control = mock_zaxis_control, max_lead_distance = 0)
        self.controller.start()
        self.wait_for_controller()
        expected_calls = [ call.move_up(), call.stop(), call.stop(), call.close()]
        actual = [ c for c in mock_zaxis_control.mock_calls if c != call.__nonzero__() ]
        self.assertEquals(expected_calls, actual)

    def test_if_draw_command_start_and_current_pos_are_not_the_same_should_move_to_new_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ 
            LateralDraw([0.0,0.0],[0.0,0.0],2.0), 
            LateralDraw([2.0,2.0],[-1.0,-1.0],2.0)
             ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.call_count = 3
        mock_path_to_audio.process.call_count = 3
        mock_laser_control.set_laser_off.assert_called_with()
        self.assertEqual(([0.0,0.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])

    def test_if_move_command_start_and_current_pos_are_not_the_same_should_move_to_new_posisition(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralMove([0.0,0.0],[0.0,0.0],2.0), LateralMove([2.0,2.0],[-1.0,-1.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        mock_laser_control.modulate.call_count = 2
        mock_path_to_audio.process.call_count = 2
        mock_laser_control.set_laser_off.assert_called_with()
        self.assertEqual(([0.0,0.0,0.0],[-1.0,-1.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])

    def test_should_ignore_z_in_layer_if_z_axis_none(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator,None)
        self.controller.start()

        self.wait_for_controller()

        self.assertEqual(2,mock_path_to_audio.process.call_count)
        mock_path_to_audio.process.assert_called_with([2.0,2.0,0.0],[0.0,0.0,1.0],2.0)

    def test_zaxis_should_be_waited_for_buy_outputing_laser_off_signal(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        zaxis_return_values = [ 0.0,0.0, 0.25, 0.75, 1.0,1.0 ]
        def z_axis_side_effect():
            return zaxis_return_values.pop(0)
        mock_zaxis.current_z_location_mm = z_axis_side_effect

        test_layer1 = Layer(0.0, [ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        test_layer2 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1,test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, mock_zaxis)
        self.controller.start()

        self.wait_for_controller()

        mock_zaxis.start.assert_called_with()
        self.assertEqual(4, mock_path_to_audio.process.call_count)
        self.assertEqual(2, mock_laser_control.set_laser_off.call_count)
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[1][0])
        self.assertEqual(([2.0,2.0,0.0],[2.0,2.0,0.0],2.0), mock_path_to_audio.process.call_args_list[2][0])

    def test_stop_should_close_all_processes_cleanly(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)

        self.controller.stop()

        time.sleep(0.1)

        mock_zaxis.stop.assert_called_with()
        mock_audio_writer.close.assert_called_with()

    def test_stop_should_close_all_processes_cleanly_while_waiting_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 0.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =   Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)

        self.controller.stop()

        self.wait_for_controller()

        mock_zaxis.stop.assert_called_with()
        mock_audio_writer.close.assert_called_with()

    def test_stop_should_close_all_processes_cleanly_while_working_on_commands(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()
        time.sleep(0.1)

        self.controller.stop()
        time.sleep(0.1)

        mock_audio_writer.close.assert_called_with()
        
        self.wait_for_controller()


    def test_set_waiting_while_wating_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 0.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value = Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.01)
        actual = self.controller.get_status()['waiting_for_drips']
        self.controller.stop()

        self.wait_for_controller()

        self.assertTrue(actual)

    def test_should_update_layer_height(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        expected_model_height = 32.7
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 23.2
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value = Layer(expected_model_height,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()
        time.sleep(0.01)
        self.controller.stop()

        self.wait_for_controller()
        actual = self.controller.get_status()['model_height']

        self.assertEquals(expected_model_height,actual)

    def test_set_waiting_while_not_wating_for_z(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_zaxis = mock_ZAxis.return_value
        mock_zaxis.current_z_location_mm.return_value = 1.0
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator,mock_zaxis)
        self.controller.start()

        time.sleep(0.1)
        actual = self.controller.get_status()['waiting_for_drips']
        self.controller.stop()

        self.wait_for_controller()

        self.assertFalse(actual)
        
    def test_should_update_machine_status(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, self.controller.get_status()['current_layer'])
        self.assertEquals('Complete',self.controller.get_status()['status'])

    def test_should_record_errors_and_abort(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_layer_generator.next.return_value =  Layer(1.0,[ LateralDraw([0.0,0.0],[2.0,2.0],2.0) ])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(1, len(self.controller.get_status()['errors']))
        self.assertEquals("Something Broke", self.controller.get_status()['errors'][0]['message'])

    def test_should_record_errors_and_continue_when_abort_on_error_is_false(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        test_layer1 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        test_layer2 = Layer(0.0,[ LateralDraw([0.0,0.0],[2.0,2.0],100.0) ])
        stub_layer_generator = StubLayerGenerator([test_layer1, test_layer2])
        mock_path_to_audio.process.side_effect = Exception("Something Broke")
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator, abort_on_error = False)
        self.controller.start()

        self.wait_for_controller()

        self.assertEquals(2, len(self.controller.get_status()['errors']))

    def test_should_change_layer_generator(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value

        generator1 = SinglePointGenerator([1.0,1.0])
        generator2 = SinglePointGenerator([0.0,0.0])

        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,generator1)
        self.controller.start()
        time.sleep(0.1)
        pre_switch = mock_path_to_audio.process.call_args
        self.controller.change_generator(generator2)
        time.sleep(0.1)
        post_switch = mock_path_to_audio.process.call_args
        self.controller.stop()
        self.wait_for_controller()

        self.assertEquals( ([1.0,1.0,0.0],[1.0,1.0,0.0],100.0), pre_switch[0] )
        self.assertEquals( ([0.0,0.0,0.0],[0.0,0.0,0.0],100.0), post_switch[0] )

    def test_stop_should_stop_working_on_commands_when_generator_changed(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        test_layer1 = Layer(1.0, [ LateralDraw([2.0,2.0],[0.0,0.0],2.0) for x in range(0,32768)])
        stub_layer_generator1 = StubLayerGenerator([test_layer1])
        test_layer2 = Layer(1.0, [ LateralDraw([0.0,0.0],[0.0,0.0],2.0)] )
        stub_layer_generator2 = StubLayerGenerator([test_layer2])
        mock_path_to_audio.process.return_value = "SomeAudio"
        mock_laser_control.modulate.return_value = "SomeModulatedAudio"
        self.controller = Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,stub_layer_generator1)
        self.controller.start()
        time.sleep(0.1)

        self.controller.change_generator(stub_layer_generator2)
        time.sleep(0.1)

        mock_path_to_audio.process.assert_called_with([0.0,0.0,1.0],[0.0,0.0,1.0],2.0)
        
        self.wait_for_controller()


    def test_init_should_set_call_back_on_zaxis(self, mock_LayerGenerator,mock_AudioWriter,mock_PathToAudio,mock_ZAxis,mock_LaserControl):
        mock_laser_control = mock_LaserControl.return_value
        mock_path_to_audio = mock_PathToAudio.return_value
        mock_audio_writer = mock_AudioWriter.return_value
        mock_layer_generator = mock_LayerGenerator.return_value
        mock_zaxis = mock_ZAxis.return_value
        Controller(mock_laser_control,mock_path_to_audio,mock_audio_writer,mock_layer_generator, mock_zaxis)

        self.assertTrue(mock_zaxis.set_drip_call_back.called)