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_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_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_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_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_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_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_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 __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()
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_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_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)
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 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 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_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_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_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_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 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 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 __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()
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)
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()
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()
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')
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')
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')
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)