AVT相机arm版本SDK
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
|
||||
from vimba import *
|
||||
|
||||
|
||||
class CamAncillaryDataTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.chunk_mode = self.cam.get_feature_by_name('ChunkModeActive')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'ChunkModeActive\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_ancillary_data_access(self):
|
||||
# Expectation: Ancillary Data is None if ChunkMode is disable.
|
||||
# If ChunkMode is enabled Ancillary Data shall not be None.
|
||||
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
# Disable ChunkMode, acquire frame: Ancillary Data must be None
|
||||
self.chunk_mode.set(False)
|
||||
self.assertIsNone(self.cam.get_frame().get_ancillary_data())
|
||||
|
||||
# Enable ChunkMode, acquire frame: Ancillary Data must not be None
|
||||
self.chunk_mode.set(True)
|
||||
self.assertIsNotNone(self.cam.get_frame().get_ancillary_data())
|
||||
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
|
||||
def test_ancillary_data_context_manager_reentrancy(self):
|
||||
# Expectation: Ancillary Data Context Manager must be reentrant.
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
self.chunk_mode.set(True)
|
||||
frame = self.cam.get_frame()
|
||||
anc_data = frame.get_ancillary_data()
|
||||
|
||||
with anc_data:
|
||||
with anc_data:
|
||||
with anc_data:
|
||||
pass
|
||||
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
|
||||
def test_ancillary_data_api_context_sensitity(self):
|
||||
# Expectation: Ancillary Data implements a Context Manager, outside of with-scope
|
||||
# a runtime error should be raised on all feature related methods accessed outside of the
|
||||
# context.
|
||||
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
self.chunk_mode.set(True)
|
||||
frame = self.cam.get_frame()
|
||||
anc_data = frame.get_ancillary_data()
|
||||
|
||||
# Check Access Outside Context
|
||||
self.assertRaises(RuntimeError, anc_data.get_all_features)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_type, IntFeature)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_category, '/ChunkData')
|
||||
self.assertRaises(RuntimeError, anc_data.get_feature_by_name, 'ChunkExposureTime')
|
||||
|
||||
with anc_data:
|
||||
# Check Access after Context entry
|
||||
self.assertNoRaise(anc_data.get_all_features)
|
||||
self.assertNoRaise(anc_data.get_features_by_type, IntFeature)
|
||||
self.assertNoRaise(anc_data.get_features_by_category, '/ChunkData')
|
||||
self.assertNoRaise(anc_data.get_feature_by_name, 'ChunkExposureTime')
|
||||
|
||||
# Check Access after Context leaving
|
||||
self.assertRaises(RuntimeError, anc_data.get_all_features)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_type, IntFeature)
|
||||
self.assertRaises(RuntimeError, anc_data.get_features_by_category, '/ChunkData')
|
||||
self.assertRaises(RuntimeError, anc_data.get_feature_by_name, 'ChunkExposureTime')
|
||||
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
|
||||
def test_ancillary_data_removed_attrs(self):
|
||||
# Expectation: Ancillary Data are lightweight features. Calling most Feature-Methods that
|
||||
# call VimbaC Features would cause an internal error. Those error prone methods
|
||||
# shall raise a RuntimeError on call.
|
||||
|
||||
old_state = self.chunk_mode.get()
|
||||
|
||||
try:
|
||||
self.chunk_mode.set(True)
|
||||
frame = self.cam.get_frame()
|
||||
anc_data = frame.get_ancillary_data()
|
||||
|
||||
with anc_data:
|
||||
for feat in anc_data.get_all_features():
|
||||
self.assertRaises(RuntimeError, feat.get_access_mode)
|
||||
self.assertRaises(RuntimeError, feat.is_readable)
|
||||
self.assertRaises(RuntimeError, feat.is_writeable)
|
||||
self.assertRaises(RuntimeError, feat.register_change_handler)
|
||||
self.assertRaises(RuntimeError, feat.get_range)
|
||||
self.assertRaises(RuntimeError, feat.get_increment)
|
||||
self.assertRaises(RuntimeError, feat.set)
|
||||
finally:
|
||||
self.chunk_mode.set(old_state)
|
||||
422
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/camera_test.py
Normal file
422
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/camera_test.py
Normal file
@@ -0,0 +1,422 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import threading
|
||||
import os
|
||||
|
||||
from vimba import *
|
||||
from vimba.frame import *
|
||||
|
||||
|
||||
def dummy_frame_handler(cam: Camera, frame: Frame):
|
||||
pass
|
||||
|
||||
|
||||
class CamCameraTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
self.cam.set_access_mode(AccessMode.Full)
|
||||
|
||||
def tearDown(self):
|
||||
self.cam.set_access_mode(AccessMode.Full)
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_camera_context_manager_access_mode(self):
|
||||
# Expectation: Entering Context must not throw in cases where the current access mode is
|
||||
# within get_permitted_access_modes()
|
||||
|
||||
permitted_modes = self.cam.get_permitted_access_modes()
|
||||
|
||||
for mode in permitted_modes:
|
||||
self.cam.set_access_mode(mode)
|
||||
|
||||
try:
|
||||
with self.cam:
|
||||
pass
|
||||
|
||||
except BaseException:
|
||||
self.fail()
|
||||
|
||||
def test_camera_context_manager_feature_discovery(self):
|
||||
# Expectation: Outside of context, all features must be cleared,
|
||||
# inside of context all features must be detected.
|
||||
with self.cam:
|
||||
self.assertNotEqual(self.cam.get_all_features(), ())
|
||||
|
||||
def test_camera_access_mode(self):
|
||||
# Expectation: set/get access mode
|
||||
self.cam.set_access_mode(AccessMode.None_)
|
||||
self.assertEqual(self.cam.get_access_mode(), AccessMode.None_)
|
||||
self.cam.set_access_mode(AccessMode.Full)
|
||||
self.assertEqual(self.cam.get_access_mode(), AccessMode.Full)
|
||||
self.cam.set_access_mode(AccessMode.Read)
|
||||
self.assertEqual(self.cam.get_access_mode(), AccessMode.Read)
|
||||
|
||||
def test_camera_get_id(self):
|
||||
# Expectation: get decoded camera id
|
||||
self.assertTrue(self.cam.get_id())
|
||||
|
||||
def test_camera_get_name(self):
|
||||
# Expectation: get decoded camera name
|
||||
self.assertTrue(self.cam.get_name())
|
||||
|
||||
def test_camera_get_model(self):
|
||||
# Expectation: get decoded camera model
|
||||
self.assertTrue(self.cam.get_model())
|
||||
|
||||
def test_camera_get_serial(self):
|
||||
# Expectation: get decoded camera serial
|
||||
self.assertTrue(self.cam.get_serial())
|
||||
|
||||
def test_camera_get_permitted_access_modes(self):
|
||||
# Expectation: get currently permitted access modes
|
||||
expected = (AccessMode.None_, AccessMode.Full, AccessMode.Read, AccessMode.Config)
|
||||
|
||||
for mode in self.cam.get_permitted_access_modes():
|
||||
self.assertIn(mode, expected)
|
||||
|
||||
def test_camera_get_interface_id(self):
|
||||
# Expectation: get interface Id this camera is connected to
|
||||
self.assertTrue(self.cam.get_interface_id())
|
||||
|
||||
def test_camera_get_features_affected(self):
|
||||
# Expectation: Features that affect other features shall return a set of affected feature
|
||||
# Features that don't affect other features shall return (). If a Feature is supplied that
|
||||
# is not associated with that camera, a TypeError must be raised.
|
||||
|
||||
with self.cam:
|
||||
try:
|
||||
affect = self.cam.get_feature_by_name('Height')
|
||||
|
||||
except VimbaFeatureError as e:
|
||||
raise unittest.SkipTest('Failed to lookup Feature Height') from e
|
||||
|
||||
try:
|
||||
not_affect = self.cam.get_feature_by_name('AcquisitionFrameCount')
|
||||
|
||||
except VimbaFeatureError as e:
|
||||
raise unittest.SkipTest('Failed to lookup Feature AcquisitionFrameCount') from e
|
||||
|
||||
self.assertEqual(self.cam.get_features_affected_by(not_affect), ())
|
||||
|
||||
try:
|
||||
payload_size = self.cam.get_feature_by_name('PayloadSize')
|
||||
|
||||
except VimbaFeatureError as e:
|
||||
raise unittest.SkipTest('Failed to lookup Feature PayloadSize') from e
|
||||
|
||||
self.assertIn(payload_size, self.cam.get_features_affected_by(affect))
|
||||
|
||||
def test_camera_frame_generator_limit_set(self):
|
||||
# Expectation: The Frame generator fetches the given number of images.
|
||||
with self.cam:
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(0)]), 0)
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(1)]), 1)
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(7)]), 7)
|
||||
self.assertEqual(len([i for i in self.cam.get_frame_generator(11)]), 11)
|
||||
|
||||
def test_camera_frame_generator_error(self):
|
||||
# Expectation: The Frame generator raises a ValueError on a
|
||||
# negative limit and the camera raises an ValueError
|
||||
# if the camera is not opened.
|
||||
|
||||
# generator execution must throw if streaming is enabled
|
||||
with self.cam:
|
||||
# Check limits
|
||||
self.assertRaises(ValueError, self.cam.get_frame_generator, -1)
|
||||
self.assertRaises(ValueError, self.cam.get_frame_generator, 1, 0)
|
||||
self.assertRaises(ValueError, self.cam.get_frame_generator, 1, -1)
|
||||
|
||||
self.cam.start_streaming(dummy_frame_handler, 5)
|
||||
|
||||
self.assertRaises(VimbaCameraError, self.cam.get_frame)
|
||||
self.assertRaises(VimbaCameraError, next, self.cam.get_frame_generator(1))
|
||||
|
||||
# Stop Streaming: Everything should be fine.
|
||||
self.cam.stop_streaming()
|
||||
self.assertNoRaise(self.cam.get_frame)
|
||||
self.assertNoRaise(next, self.cam.get_frame_generator(1))
|
||||
|
||||
def test_camera_get_frame(self):
|
||||
# Expectation: Gets single Frame without any exception. Image data must be set.
|
||||
# If a zero or negative timeouts must lead to a ValueError.
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.get_frame, 0)
|
||||
self.assertRaises(ValueError, self.cam.get_frame, -1)
|
||||
|
||||
self.assertNoRaise(self.cam.get_frame)
|
||||
self.assertEqual(type(self.cam.get_frame()), Frame)
|
||||
|
||||
def test_camera_capture_error_outside_vimba_scope(self):
|
||||
# Expectation: Camera access outside of Vimba scope must lead to a RuntimeError
|
||||
gener = None
|
||||
|
||||
with self.cam:
|
||||
gener = self.cam.get_frame_generator(1)
|
||||
|
||||
# Shutdown API
|
||||
self.vimba._shutdown()
|
||||
|
||||
# Access invalid Iterator
|
||||
self.assertRaises(RuntimeError, next, gener)
|
||||
|
||||
def test_camera_capture_error_outside_camera_scope(self):
|
||||
# Expectation: Camera access outside of Camera scope must lead to a RuntimeError
|
||||
gener = None
|
||||
|
||||
with self.cam:
|
||||
gener = self.cam.get_frame_generator(1)
|
||||
|
||||
self.assertRaises(RuntimeError, next, gener)
|
||||
|
||||
def test_camera_capture_timeout(self):
|
||||
# Expectation: Camera access outside of Camera scope must lead to a VimbaTimeout
|
||||
with self.cam:
|
||||
self.assertRaises(VimbaTimeout, self.cam.get_frame, 1)
|
||||
|
||||
def test_camera_is_streaming(self):
|
||||
# Expectation: After start_streaming() is_streaming() must return true. After stop it must
|
||||
# return false. If the camera context is left without stop_streaming(), leaving
|
||||
# the context must stop streaming.
|
||||
|
||||
# Normal Operation
|
||||
self.assertEqual(self.cam.is_streaming(), False)
|
||||
with self.cam:
|
||||
self.cam.start_streaming(dummy_frame_handler)
|
||||
self.assertEqual(self.cam.is_streaming(), True)
|
||||
|
||||
self.cam.stop_streaming()
|
||||
self.assertEqual(self.cam.is_streaming(), False)
|
||||
|
||||
# Missing the stream stop. Close must stop streaming
|
||||
with self.cam:
|
||||
self.cam.start_streaming(dummy_frame_handler, 5)
|
||||
self.assertEqual(self.cam.is_streaming(), True)
|
||||
|
||||
self.assertEqual(self.cam.is_streaming(), False)
|
||||
|
||||
def test_camera_streaming_error_frame_count(self):
|
||||
# Expectation: A negative or zero frame_count must lead to an value error
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.start_streaming, dummy_frame_handler, 0)
|
||||
self.assertRaises(ValueError, self.cam.start_streaming, dummy_frame_handler, -1)
|
||||
|
||||
def test_camera_streaming(self):
|
||||
# Expectation: A given frame_handler must be executed for each buffered frame.
|
||||
|
||||
class FrameHandler:
|
||||
def __init__(self, frame_count):
|
||||
self.cnt = 0
|
||||
self.frame_count = frame_count
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, cam: Camera, frame: Frame):
|
||||
self.cnt += 1
|
||||
|
||||
if self.cnt == self.frame_count:
|
||||
self.event.set()
|
||||
|
||||
timeout = 5.0
|
||||
frame_count = 10
|
||||
handler = FrameHandler(frame_count)
|
||||
|
||||
with self.cam:
|
||||
try:
|
||||
self.cam.start_streaming(handler, frame_count)
|
||||
|
||||
# Wait until the FrameHandler has been executed for each queued frame
|
||||
self.assertTrue(handler.event.wait(timeout))
|
||||
|
||||
finally:
|
||||
self.cam.stop_streaming()
|
||||
|
||||
def test_camera_streaming_queue(self):
|
||||
# Expectation: A given frame must be reused if it is enqueued again.
|
||||
|
||||
class FrameHandler:
|
||||
def __init__(self, frame_count):
|
||||
self.cnt = 0
|
||||
self.frame_count = frame_count
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, cam: Camera, frame: Frame):
|
||||
self.cnt += 1
|
||||
|
||||
if self.cnt == self.frame_count:
|
||||
self.event.set()
|
||||
|
||||
cam.queue_frame(frame)
|
||||
|
||||
timeout = 5.0
|
||||
frame_count = 5
|
||||
frame_reuse = 2
|
||||
handler = FrameHandler(frame_count * frame_reuse)
|
||||
|
||||
with self.cam:
|
||||
try:
|
||||
self.cam.start_streaming(handler, frame_count)
|
||||
|
||||
# Wait until the FrameHandler has been executed for each queued frame
|
||||
self.assertTrue(handler.event.wait(timeout))
|
||||
|
||||
finally:
|
||||
self.cam.stop_streaming()
|
||||
|
||||
def test_camera_runtime_type_check(self):
|
||||
def valid_handler(cam, frame):
|
||||
pass
|
||||
|
||||
def invalid_handler_1(cam):
|
||||
pass
|
||||
|
||||
def invalid_handler_2(cam, frame, extra):
|
||||
pass
|
||||
|
||||
self.assertRaises(TypeError, self.cam.set_access_mode, -1)
|
||||
|
||||
with self.cam:
|
||||
# Expectation: raise TypeError on passing invalid parameters
|
||||
self.assertRaises(TypeError, self.cam.get_frame, 'hi')
|
||||
self.assertRaises(TypeError, self.cam.get_features_affected_by, 'No Feature')
|
||||
self.assertRaises(TypeError, self.cam.get_features_selected_by, 'No Feature')
|
||||
self.assertRaises(TypeError, self.cam.get_features_by_type, 0.0)
|
||||
self.assertRaises(TypeError, self.cam.get_feature_by_name, 0)
|
||||
self.assertRaises(TypeError, self.cam.get_frame_generator, '3')
|
||||
self.assertRaises(TypeError, self.cam.get_frame_generator, 0, 'foo')
|
||||
self.assertRaises(TypeError, self.cam.start_streaming, valid_handler, 'no int')
|
||||
self.assertRaises(TypeError, self.cam.start_streaming, invalid_handler_1)
|
||||
self.assertRaises(TypeError, self.cam.start_streaming, invalid_handler_2)
|
||||
self.assertRaises(TypeError, self.cam.save_settings, 0, PersistType.All)
|
||||
self.assertRaises(TypeError, self.cam.save_settings, 'foo.xml', 'false type')
|
||||
|
||||
def test_camera_save_load_settings(self):
|
||||
# Expectation: After settings export a settings change must be reverted by loading a
|
||||
# Previously saved configuration.
|
||||
|
||||
file_name = 'test_save_load_settings.xml'
|
||||
|
||||
with self.cam:
|
||||
feat_height = self.cam.get_feature_by_name('Height')
|
||||
old_val = feat_height.get()
|
||||
|
||||
self.cam.save_settings(file_name, PersistType.All)
|
||||
|
||||
min_, max_ = feat_height.get_range()
|
||||
inc = feat_height.get_increment()
|
||||
|
||||
feat_height.set(max_ - min_ - inc)
|
||||
|
||||
self.cam.load_settings(file_name, PersistType.All)
|
||||
os.remove(file_name)
|
||||
|
||||
self.assertEqual(old_val, feat_height.get())
|
||||
|
||||
def test_camera_save_settings_verify_path(self):
|
||||
# Expectation: Valid files end with .xml and can be either a absolute path or relative
|
||||
# path to the given File. Everything else is a ValueError.
|
||||
|
||||
valid_paths = (
|
||||
'valid1.xml',
|
||||
os.path.join('.', 'valid2.xml'),
|
||||
os.path.join('Tests', 'valid3.xml'),
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'valid4.xml'),
|
||||
)
|
||||
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.save_settings, 'inval.xm', PersistType.All)
|
||||
|
||||
for path in valid_paths:
|
||||
self.assertNoRaise(self.cam.save_settings, path, PersistType.All)
|
||||
os.remove(path)
|
||||
|
||||
def test_camera_load_settings_verify_path(self):
|
||||
# Expectation: Valid files end with .xml and must exist before before any execution.
|
||||
valid_paths = (
|
||||
'valid1.xml',
|
||||
os.path.join('.', 'valid2.xml'),
|
||||
os.path.join('Tests', 'valid3.xml'),
|
||||
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'valid4.xml'),
|
||||
)
|
||||
|
||||
with self.cam:
|
||||
self.assertRaises(ValueError, self.cam.load_settings, 'inval.xm', PersistType.All)
|
||||
|
||||
for path in valid_paths:
|
||||
self.assertRaises(ValueError, self.cam.load_settings, path, PersistType.All)
|
||||
|
||||
for path in valid_paths:
|
||||
self.cam.save_settings(path, PersistType.All)
|
||||
|
||||
self.assertNoRaise(self.cam.load_settings, path, PersistType.All)
|
||||
os.remove(path)
|
||||
|
||||
def test_camera_context_manager_reentrancy(self):
|
||||
# Expectation: Camera Context Manager must be reentrant. Multiple calls to _open
|
||||
# must be prevented (would cause VimbaC - Error)
|
||||
with self.cam:
|
||||
with self.cam:
|
||||
with self.cam:
|
||||
pass
|
||||
|
||||
def test_camera_api_context_sensitity_outside_context(self):
|
||||
# Expectation: Call set_access_mode withing with scope must raise a RuntimeError
|
||||
with self.cam:
|
||||
self.assertRaises(RuntimeError, self.cam.set_access_mode)
|
||||
|
||||
def test_camera_api_context_sensitity_inside_context(self):
|
||||
# Expectation: Most Camera related functions are only valid then called within the given
|
||||
# Context. If called from Outside a runtime error must be raised.
|
||||
self.assertRaises(RuntimeError, self.cam.read_memory)
|
||||
self.assertRaises(RuntimeError, self.cam.write_memory)
|
||||
self.assertRaises(RuntimeError, self.cam.read_registers)
|
||||
self.assertRaises(RuntimeError, self.cam.write_registers)
|
||||
self.assertRaises(RuntimeError, self.cam.get_all_features)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_affected_by)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_selected_by)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_by_type)
|
||||
self.assertRaises(RuntimeError, self.cam.get_features_by_category)
|
||||
self.assertRaises(RuntimeError, self.cam.get_feature_by_name)
|
||||
self.assertRaises(RuntimeError, self.cam.get_frame_generator)
|
||||
self.assertRaises(RuntimeError, self.cam.get_frame)
|
||||
self.assertRaises(RuntimeError, self.cam.start_streaming)
|
||||
self.assertRaises(RuntimeError, self.cam.stop_streaming)
|
||||
self.assertRaises(RuntimeError, self.cam.queue_frame)
|
||||
self.assertRaises(RuntimeError, self.cam.get_pixel_formats)
|
||||
self.assertRaises(RuntimeError, self.cam.get_pixel_format)
|
||||
self.assertRaises(RuntimeError, self.cam.set_pixel_format)
|
||||
self.assertRaises(RuntimeError, self.cam.save_settings)
|
||||
self.assertRaises(RuntimeError, self.cam.load_settings)
|
||||
@@ -0,0 +1,831 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import threading
|
||||
|
||||
from vimba import *
|
||||
from vimba.feature import *
|
||||
|
||||
|
||||
class CamBaseFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.height = self.cam.get_feature_by_name('Height')
|
||||
|
||||
except VimbaCameraError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'Height\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_name(self):
|
||||
# Expectation: Return decoded FeatureName
|
||||
self.assertEqual(self.height.get_name(), 'Height')
|
||||
|
||||
def test_get_flags(self):
|
||||
# Expectation: Return decoded FeatureFlags
|
||||
self.assertEqual(self.height.get_flags(), (FeatureFlags.Read, FeatureFlags.Write))
|
||||
|
||||
def test_get_category(self):
|
||||
# Expectation: Return decoded category
|
||||
self.assertNotEqual(self.height.get_category(), '')
|
||||
|
||||
def test_get_display_name(self):
|
||||
# Expectation: Return decoded category
|
||||
self.assertEqual(self.height.get_display_name(), 'Height')
|
||||
|
||||
def test_get_polling_time(self):
|
||||
# Expectation: Return polling time. Only volatile features return
|
||||
# anything other than zero.
|
||||
self.assertEqual(self.height.get_polling_time(), 0)
|
||||
|
||||
def test_get_unit(self):
|
||||
# Expectation: If Unit exists, return unit else return ''
|
||||
self.assertEqual(self.height.get_unit(), '')
|
||||
|
||||
def test_get_representation(self):
|
||||
# Expectation: Get numeric representation if existing else ''
|
||||
self.assertEqual(self.height.get_representation(), '')
|
||||
|
||||
def test_get_visibility(self):
|
||||
# Expectation: Get UI Visibility
|
||||
self.assertEqual(self.height.get_visibility(), FeatureVisibility.Beginner)
|
||||
|
||||
def test_get_tooltip(self):
|
||||
# Expectation: Shall not raise anything
|
||||
self.assertNoRaise(self.height.get_tooltip)
|
||||
|
||||
def test_get_description(self):
|
||||
# Expectation: Get decoded description
|
||||
self.assertNotEqual(self.height.get_description(), '')
|
||||
|
||||
def test_get_sfnc_namespace(self):
|
||||
# Expectation: Get decoded sfnc namespace
|
||||
self.assertNotEqual(self.height.get_sfnc_namespace(), '')
|
||||
|
||||
def test_is_streamable(self):
|
||||
# Expectation: Streamable features shall return True, others False
|
||||
self.assertNoRaise(self.height.is_streamable)
|
||||
|
||||
def test_has_affected_features(self):
|
||||
# Expectation:Features that affect features shall return True, others False
|
||||
self.assertTrue(self.height.has_affected_features())
|
||||
|
||||
def test_has_selected_features(self):
|
||||
# Expectation:Features that select features shall return True, others False
|
||||
self.assertFalse(self.height.has_selected_features())
|
||||
|
||||
def test_get_access_mode(self):
|
||||
# Expectation: Read/Write Features return (True, True), ReadOnly return (True, False)
|
||||
self.assertEqual(self.height.get_access_mode(), (True, True))
|
||||
|
||||
def test_is_readable(self):
|
||||
# Expectation: True if feature grant read access else False
|
||||
self.assertTrue(self.height.is_readable())
|
||||
|
||||
def test_is_writeable(self):
|
||||
# Expectation: True if feature grant write access else False
|
||||
self.assertTrue(self.height.is_writeable())
|
||||
|
||||
def test_change_handler(self):
|
||||
# Expectation: A given change handler is executed on value change.
|
||||
# Adding the same handler multiple times shall not lead to multiple executions.
|
||||
# The same goes for double unregister.
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.event = threading.Event()
|
||||
self.call_cnt = 0
|
||||
|
||||
def __call__(self, feat):
|
||||
self.call_cnt += 1
|
||||
self.event.set()
|
||||
|
||||
handler = Handler()
|
||||
|
||||
self.height.register_change_handler(handler)
|
||||
self.height.register_change_handler(handler)
|
||||
|
||||
tmp = self.height.get()
|
||||
|
||||
min_, _ = self.height.get_range()
|
||||
inc = self.height.get_increment()
|
||||
|
||||
if min_ <= tmp - inc:
|
||||
self.height.set(tmp - inc)
|
||||
|
||||
else:
|
||||
self.height.set(tmp + inc)
|
||||
|
||||
handler.event.wait()
|
||||
|
||||
self.height.unregister_change_handler(handler)
|
||||
self.height.unregister_change_handler(handler)
|
||||
|
||||
self.height.set(tmp)
|
||||
|
||||
self.assertEqual(handler.call_cnt, 1)
|
||||
|
||||
def test_stringify_features(self):
|
||||
# Expectation: Each Feature must have a __str__ method. Depending on the Feature
|
||||
# current Values are queried, this can fail. In those cases, all exceptions are
|
||||
# fetched -> all features must be strinify able without raising any exception
|
||||
for feat in self.vimba.get_all_features():
|
||||
self.assertNoRaise(str, feat)
|
||||
|
||||
for feat in self.cam.get_all_features():
|
||||
self.assertNoRaise(str, feat)
|
||||
|
||||
|
||||
class CamBoolFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.feat = self.vimba.get_feature_by_name('UsbTLIsPresent')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'UsbTLIsPresent\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: BoolFeature must return BoolFeature on get_type
|
||||
self.assertEqual(self.feat.get_type(), BoolFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: returns current boolean value.
|
||||
self.assertNoRaise(self.feat.get)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation: Raises invalid Access on non-writeable features.
|
||||
self.assertRaises(VimbaFeatureError, self.feat.set, True)
|
||||
|
||||
|
||||
class CamCommandFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.feat = self.vimba.get_feature_by_name('ActionCommand')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'ActionCommand\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: CommandFeature must return CommandFeature on get_type
|
||||
self.assertEqual(self.feat.get_type(), CommandFeature)
|
||||
|
||||
|
||||
class CamEnumFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.feat_r = self.cam.get_feature_by_name('DeviceScanType')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'DeviceScanType\' not available.')
|
||||
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('AcquisitionMode')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'AcquisitionMode\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: EnumFeature must return EnumFeature on get_type
|
||||
self.assertEqual(self.feat_r.get_type(), EnumFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), EnumFeature)
|
||||
|
||||
def test_entry_as_bytes(self):
|
||||
# Expectation: Get EnumEntry as encoded byte sequence
|
||||
expected = b'MultiFrame'
|
||||
entry = self.feat_rw.get_entry('MultiFrame')
|
||||
|
||||
self.assertEqual(bytes(entry), expected)
|
||||
|
||||
def test_entry_as_tuple(self):
|
||||
# Expectation: Get EnumEntry as (str, int)
|
||||
entry = self.feat_rw.get_entry('MultiFrame')
|
||||
self.assertEqual(entry.as_tuple(), self.feat_rw.get_entry(int(entry)).as_tuple())
|
||||
|
||||
def test_get_all_entries(self):
|
||||
# Expectation: Get all possible enum entries regardless of the availability
|
||||
expected = (self.feat_r.get_entry('Areascan'),)
|
||||
|
||||
for e in expected:
|
||||
self.assertIn(e, self.feat_r.get_all_entries())
|
||||
|
||||
expected = (
|
||||
self.feat_rw.get_entry('SingleFrame'),
|
||||
self.feat_rw.get_entry('MultiFrame'),
|
||||
self.feat_rw.get_entry('Continuous')
|
||||
)
|
||||
|
||||
for e in expected:
|
||||
self.assertIn(e, self.feat_rw.get_all_entries())
|
||||
|
||||
def test_get_avail_entries(self):
|
||||
# Expectation: All returned enum entries must be available
|
||||
for e in self.feat_r.get_available_entries():
|
||||
self.assertTrue(e.is_available())
|
||||
|
||||
for e in self.feat_rw.get_available_entries():
|
||||
self.assertTrue(e.is_available())
|
||||
|
||||
def test_get_entry_int(self):
|
||||
# Expectation: Lookup a given entry by using an int as key.
|
||||
# Invalid keys must return VimbaFeatureError.
|
||||
|
||||
expected = self.feat_r.get_all_entries()[0]
|
||||
self.assertEqual(self.feat_r.get_entry(int(expected)), expected)
|
||||
|
||||
expected = self.feat_rw.get_all_entries()[1]
|
||||
self.assertEqual(self.feat_rw.get_entry(int(expected)), expected)
|
||||
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.get_entry, -1)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.get_entry, -1)
|
||||
|
||||
def test_get_entry_str(self):
|
||||
# Expectation: Lookup a given entry by using a str as key.
|
||||
# Invalid keys must return VimbaFeatureError.
|
||||
|
||||
expected = self.feat_r.get_all_entries()[0]
|
||||
self.assertEqual(self.feat_r.get_entry(str(expected)), expected)
|
||||
|
||||
expected = self.feat_rw.get_all_entries()[1]
|
||||
self.assertEqual(self.feat_rw.get_entry(str(expected)), expected)
|
||||
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.get_entry, 'Should be invalid')
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.get_entry, 'Should be invalid')
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get must return the current value.
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_set_entry(self):
|
||||
# Expectation: Set given enum entry if feature is writable.
|
||||
# Raises:
|
||||
# - VimbaFeatureError if enum entry is from other enum feature.
|
||||
# - VimbaFeatureError if feature is read only
|
||||
|
||||
# Read Only Feature
|
||||
entry = self.feat_r.get_all_entries()[0]
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, entry)
|
||||
|
||||
# Read/Write Feature
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
# Normal operation
|
||||
self.assertNoRaise(self.feat_rw.set, self.feat_rw.get_entry(2))
|
||||
self.assertEqual(self.feat_rw.get(), self.feat_rw.get_entry(2))
|
||||
|
||||
# Provoke FeatureError by setting the feature from the ReadOnly entry.
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, entry)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
def test_set_str(self):
|
||||
# Expectation: Set given enum entry string value if feature is writable.
|
||||
# Raises:
|
||||
# - VimbaFeatureError if given string is not associated with this feature.
|
||||
# - VimbaFeatureError if feature is read only
|
||||
|
||||
# Read Only Feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, str(self.feat_r.get_entry(0)))
|
||||
|
||||
# Read/Write Feature
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
# Normal operation
|
||||
self.assertNoRaise(self.feat_rw.set, str(self.feat_rw.get_entry(2)))
|
||||
self.assertEqual(self.feat_rw.get(), self.feat_rw.get_entry(2))
|
||||
|
||||
# Provoke FeatureError by an invalid enum value
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, 'Hopefully invalid')
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
def test_set_int(self):
|
||||
# Expectation: Set given enum entry int value if feature is writable.
|
||||
# Raises:
|
||||
# - VimbaFeatureError if given int is not associated with this feature.
|
||||
# - VimbaFeatureError if feature is read only
|
||||
|
||||
# Read Only Feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, int(self.feat_r.get_entry(0)))
|
||||
|
||||
# Read/Write Feature
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
# Normal operation
|
||||
self.assertNoRaise(self.feat_rw.set, int(self.feat_rw.get_entry(2)))
|
||||
self.assertEqual(self.feat_rw.get(), self.feat_rw.get_entry(2))
|
||||
|
||||
# Provoke FeatureError by an invalid enum value
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, -23)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expected behavior: A set operation within a change handler must
|
||||
# Raise a VimbaFeatureError to prevent an endless handler execution.
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
# Trigger change handler and wait for callback execution.
|
||||
self.feat_rw.set(self.feat_rw.get())
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
|
||||
class CamFloatFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.feat_r = self.vimba.get_feature_by_name('Elapsed')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'Elapsed\' not available.')
|
||||
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('ExposureTime')
|
||||
|
||||
except VimbaFeatureError:
|
||||
# Some Cameras name ExposureTime as ExposureTimeAbs
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('ExposureTimeAbs')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'ExposureTime\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: FloatFeature returns FloatFeature on get_type.
|
||||
self.assertEqual(self.feat_r.get_type(), FloatFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), FloatFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get current value.
|
||||
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_get_range(self):
|
||||
# Expectation: Get value range. Raise VimbaFeatureError on non-read access.
|
||||
self.assertNoRaise(self.feat_r.get_range)
|
||||
self.assertNoRaise(self.feat_rw.get_range)
|
||||
|
||||
def test_get_increment(self):
|
||||
# Expectation: Get value increment if existing. If this Feature has no
|
||||
# increment, None is returned.
|
||||
|
||||
self.assertNoRaise(self.feat_r.get_increment)
|
||||
self.assertNoRaise(self.feat_rw.get_increment)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation: Set value. Errors:
|
||||
# VimbaFeatureError if access right are not writable
|
||||
# VimbaFeatureError if value is out of bounds
|
||||
|
||||
# Read only feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, 0.0)
|
||||
|
||||
# Read/Write Feature
|
||||
old_value = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
delta = 0.1
|
||||
|
||||
# Range test
|
||||
min_, max_ = self.feat_rw.get_range()
|
||||
|
||||
# Within bounds (no error)
|
||||
self.assertNoRaise(self.feat_rw.set, min_)
|
||||
self.assertAlmostEqual(self.feat_rw.get(), min_)
|
||||
self.assertNoRaise(self.feat_rw.set, max_)
|
||||
self.assertAlmostEqual(self.feat_rw.get(), max_)
|
||||
|
||||
# Out of bounds (must raise)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, min_ - delta)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, max_ + delta)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_value)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expectation: Calling set within change_handler must raise an VimbaFeatureError
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
# Trigger change handler and wait for callback execution.
|
||||
self.feat_rw.set(self.feat_rw.get())
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
|
||||
class CamIntFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
try:
|
||||
self.feat_r = self.cam.get_feature_by_name('HeightMax')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'HeightMax\' not available.')
|
||||
|
||||
try:
|
||||
self.feat_rw = self.cam.get_feature_by_name('Height')
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Required Feature \'Height\' not available.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: IntFeature must return IntFeature on get_type
|
||||
self.assertEqual(self.feat_r.get_type(), IntFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), IntFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get current value
|
||||
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_get_range(self):
|
||||
# Expectation: Get range of accepted values
|
||||
self.assertNoRaise(self.feat_r.get_range)
|
||||
self.assertNoRaise(self.feat_rw.get_range)
|
||||
|
||||
def test_get_increment(self):
|
||||
# Expectation: Get step between valid values
|
||||
self.assertNoRaise(self.feat_r.get_increment)
|
||||
self.assertNoRaise(self.feat_rw.get_increment)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation: Set value or raise VimbaFeatureError under the following conditions.
|
||||
# 1) Invalid Access Rights
|
||||
# 2) Misaligned value.
|
||||
# 3) Out-of-bounds Access
|
||||
|
||||
# Read only feature
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, 0)
|
||||
|
||||
# Writable feature
|
||||
old_value = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
inc = self.feat_rw.get_increment()
|
||||
min_, max_ = self.feat_rw.get_range()
|
||||
|
||||
# Normal usage
|
||||
self.assertNoRaise(self.feat_rw.set, min_)
|
||||
self.assertEqual(self.feat_rw.get(), min_)
|
||||
self.assertNoRaise(self.feat_rw.set, max_)
|
||||
self.assertEqual(self.feat_rw.get(), max_)
|
||||
|
||||
# Out of bounds access.
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, min_ - inc)
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, max_ + inc)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_value)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expectation: Setting a value within a Callback must raise a VimbaFeatureError
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
old_entry = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
# Trigger change handler and wait for callback execution.
|
||||
min_, _ = self.feat_rw.get_range()
|
||||
inc = self.feat_rw.get_increment()
|
||||
|
||||
if min_ <= (old_entry - inc):
|
||||
self.feat_rw.set(old_entry - inc)
|
||||
|
||||
else:
|
||||
self.feat_rw.set(old_entry + inc)
|
||||
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
self.feat_rw.set(old_entry)
|
||||
|
||||
|
||||
class CamStringFeatureTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
try:
|
||||
self.cam._open()
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to open Camera.') from e
|
||||
|
||||
self.feat_r = None
|
||||
feats = self.cam.get_features_by_type(StringFeature)
|
||||
|
||||
for feat in feats:
|
||||
if feat.get_access_mode() == (True, False):
|
||||
self.feat_r = feat
|
||||
|
||||
if self.feat_r is None:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Test requires read only StringFeature.')
|
||||
|
||||
self.feat_rw = None
|
||||
feats = self.cam.get_features_by_type(StringFeature)
|
||||
|
||||
for feat in feats:
|
||||
if feat.get_access_mode() == (True, True):
|
||||
self.feat_rw = feat
|
||||
|
||||
if self.feat_rw is None:
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
self.skipTest('Test requires read/write StringFeature.')
|
||||
|
||||
def tearDown(self):
|
||||
self.cam._close()
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_get_type(self):
|
||||
# Expectation: StringFeature must return StringFeature on get_type
|
||||
self.assertEqual(self.feat_r.get_type(), StringFeature)
|
||||
self.assertEqual(self.feat_rw.get_type(), StringFeature)
|
||||
|
||||
def test_get(self):
|
||||
# Expectation: Get current value without raising an exception
|
||||
self.assertNoRaise(self.feat_r.get)
|
||||
self.assertNoRaise(self.feat_rw.get)
|
||||
|
||||
def test_get_max_length(self):
|
||||
# Expectation: Get maximum string length
|
||||
self.assertNoRaise(self.feat_r.get_max_length)
|
||||
self.assertNoRaise(self.feat_rw.get_max_length)
|
||||
|
||||
def test_set(self):
|
||||
# Expectation:
|
||||
# 1) Setting a read only feature must raise a VimbaFeatureError
|
||||
# 2) Setting a read/wrtie must raise VimbaFeatureError if the string is
|
||||
# longer than max length
|
||||
# 3) Setting a read/write feature must work if string is long enough
|
||||
|
||||
# Ensure Expectation 1
|
||||
self.assertRaises(VimbaFeatureError, self.feat_r.set, self.feat_r.get())
|
||||
self.assertNoRaise(self.feat_rw.set, self.feat_rw.get())
|
||||
|
||||
# Ensure Expectation 2
|
||||
old_val = self.feat_rw.get()
|
||||
|
||||
try:
|
||||
invalid = 'a' * self.feat_rw.get_max_length()
|
||||
self.assertRaises(VimbaFeatureError, self.feat_rw.set, invalid)
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_val)
|
||||
|
||||
# Ensure Expectation 3
|
||||
try:
|
||||
valid = 'a' * (self.feat_rw.get_max_length() - 1)
|
||||
self.assertNoRaise(self.feat_rw.set, valid)
|
||||
self.assertEqual(valid, self.feat_rw.get())
|
||||
|
||||
finally:
|
||||
self.feat_rw.set(old_val)
|
||||
|
||||
def test_set_in_callback(self):
|
||||
# Expectation: Setting a value within a Callback must raise a VimbaFeatureError
|
||||
|
||||
class Handler:
|
||||
def __init__(self):
|
||||
self.raised = False
|
||||
self.event = threading.Event()
|
||||
|
||||
def __call__(self, feat):
|
||||
try:
|
||||
feat.set(feat.get())
|
||||
|
||||
except VimbaFeatureError:
|
||||
self.raised = True
|
||||
|
||||
self.event.set()
|
||||
|
||||
try:
|
||||
handler = Handler()
|
||||
self.feat_rw.register_change_handler(handler)
|
||||
|
||||
self.feat_rw.set(self.feat_rw.get())
|
||||
|
||||
handler.event.wait()
|
||||
|
||||
self.assertTrue(handler.raised)
|
||||
|
||||
finally:
|
||||
self.feat_rw.unregister_change_handler(handler)
|
||||
206
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/frame_test.py
Normal file
206
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/frame_test.py
Normal file
@@ -0,0 +1,206 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import copy
|
||||
import ctypes
|
||||
|
||||
from vimba import *
|
||||
from vimba.frame import *
|
||||
|
||||
|
||||
class CamFrameTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
self.vimba._startup()
|
||||
|
||||
try:
|
||||
self.cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
|
||||
except VimbaCameraError as e:
|
||||
self.vimba._shutdown()
|
||||
raise Exception('Failed to lookup Camera.') from e
|
||||
|
||||
def tearDown(self):
|
||||
self.vimba._shutdown()
|
||||
|
||||
def test_verify_buffer(self):
|
||||
# Expectation: A Frame buffer shall have exactly the specified size on construction.
|
||||
# Allocation is performed by VimbaPython
|
||||
self.assertEqual(Frame(0, AllocationMode.AnnounceFrame).get_buffer_size(), 0)
|
||||
self.assertEqual(Frame(1024, AllocationMode.AnnounceFrame).get_buffer_size(), 1024)
|
||||
self.assertEqual(Frame(1024 * 1024, AllocationMode.AnnounceFrame).get_buffer_size(),
|
||||
1024 * 1024)
|
||||
|
||||
def test_verify_no_copy_empty_buffer_access(self):
|
||||
# Expectation: Accessing the internal buffer must not create a copy
|
||||
# frame._buffer is only set on construction if buffer is allocated by VimbaPython
|
||||
frame = Frame(10, AllocationMode.AnnounceFrame)
|
||||
self.assertEqual(id(frame._buffer), id(frame.get_buffer()))
|
||||
|
||||
def test_verify_no_copy_filled_buffer_access(self):
|
||||
# Expectation: Accessing the internal buffer must not create a copy
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
self.assertEqual(id(frame._buffer), id(frame.get_buffer()))
|
||||
|
||||
def test_get_id(self):
|
||||
# Expectation: get_id() must return None if Its locally constructed
|
||||
# else it must return the frame id.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_id())
|
||||
|
||||
with self.cam:
|
||||
self.assertIsNotNone(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_id())
|
||||
|
||||
def test_get_timestamp(self):
|
||||
# Expectation: get_timestamp() must return None if Its locally constructed
|
||||
# else it must return the timestamp.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_timestamp())
|
||||
|
||||
with self.cam:
|
||||
self.assertIsNotNone(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_timestamp())
|
||||
|
||||
def test_get_offset(self):
|
||||
# Expectation: get_offset_x() must return None if Its locally constructed
|
||||
# else it must return the offset as int. Same goes for get_offset_y()
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_offset_x())
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_offset_y())
|
||||
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
self.assertIsNotNone(frame.get_offset_x())
|
||||
self.assertIsNotNone(frame.get_offset_y())
|
||||
|
||||
def test_get_dimension(self):
|
||||
# Expectation: get_width() must return None if Its locally constructed
|
||||
# else it must return the offset as int. Same goes for get_height()
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_width())
|
||||
self.assertIsNone(Frame(0, allocation_mode).get_height())
|
||||
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
self.assertIsNotNone(frame.get_width())
|
||||
self.assertIsNotNone(frame.get_height())
|
||||
|
||||
def test_get_image_size(self):
|
||||
# Expectation: get_image_size() must return 0 if locally constructed
|
||||
# else it must return the image_size as int.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
self.assertEquals(Frame(0, allocation_mode).get_image_size(), 0)
|
||||
|
||||
with self.cam:
|
||||
self.assertNotEquals(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_image_size(), 0)
|
||||
|
||||
def test_deepcopy(self):
|
||||
# Expectation: a deepcopy must clone the frame buffer with its contents an
|
||||
# update the internally store pointer in VmbFrame struct.
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
|
||||
frame_cpy = copy.deepcopy(frame)
|
||||
|
||||
# Ensure frames and their members are not the same object
|
||||
self.assertNotEquals(id(frame), id(frame_cpy))
|
||||
self.assertNotEquals(id(frame._buffer), id(frame_cpy._buffer))
|
||||
self.assertNotEquals(id(frame._frame), id(frame_cpy._frame))
|
||||
|
||||
# Ensure that both buffers have the same size and contain the same data.
|
||||
self.assertEquals(frame.get_buffer_size(), frame_cpy.get_buffer_size())
|
||||
self.assertTrue(all(a == b for a, b in zip(frame.get_buffer(),
|
||||
frame_cpy.get_buffer())))
|
||||
|
||||
# Ensure that internal Frame Pointer points to correct buffer.
|
||||
self.assertEquals(frame._frame.buffer,
|
||||
ctypes.cast(frame._buffer, ctypes.c_void_p).value)
|
||||
|
||||
self.assertEquals(frame_cpy._frame.buffer,
|
||||
ctypes.cast(frame_cpy._buffer, ctypes.c_void_p).value)
|
||||
|
||||
self.assertEquals(frame._frame.bufferSize, frame_cpy._frame.bufferSize)
|
||||
|
||||
def test_get_pixel_format(self):
|
||||
# Expectation: Frames have an image format set after acquisition
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
self.assertNotEquals(
|
||||
self.cam.get_frame(allocation_mode=allocation_mode).get_pixel_format(), 0)
|
||||
|
||||
def test_incompatible_formats_value_error(self):
|
||||
# Expectation: Conversion into incompatible formats must lead to an value error
|
||||
for allocation_mode in AllocationMode:
|
||||
with self.subTest(f'allocation_mode={str(allocation_mode)}'):
|
||||
with self.cam:
|
||||
frame = self.cam.get_frame(allocation_mode=allocation_mode)
|
||||
|
||||
current_fmt = frame.get_pixel_format()
|
||||
convertable_fmt = current_fmt.get_convertible_formats()
|
||||
|
||||
for fmt in PixelFormat.__members__.values():
|
||||
if (fmt != current_fmt) and (fmt not in convertable_fmt):
|
||||
self.assertRaises(ValueError, frame.convert_pixel_format, fmt)
|
||||
|
||||
def test_convert_to_all_given_formats(self):
|
||||
# Expectation: A Series of Frame, each acquired with a different Pixel format
|
||||
# Must be convertible to all formats the given format claims its convertible to without any
|
||||
# errors.
|
||||
|
||||
test_frames = []
|
||||
|
||||
with self.cam:
|
||||
for fmt in self.cam.get_pixel_formats():
|
||||
self.cam.set_pixel_format(fmt)
|
||||
|
||||
frame = self.cam.get_frame()
|
||||
|
||||
self.assertEqual(fmt, frame.get_pixel_format())
|
||||
test_frames.append(frame)
|
||||
|
||||
for frame in test_frames:
|
||||
|
||||
# The test shall work on a copy to keep the original Frame untouched
|
||||
for expected_fmt in frame.get_pixel_format().get_convertible_formats():
|
||||
cpy_frame = copy.deepcopy(frame)
|
||||
cpy_frame.convert_pixel_format(expected_fmt)
|
||||
|
||||
self.assertEquals(expected_fmt, cpy_frame.get_pixel_format())
|
||||
149
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/vimba_test.py
Normal file
149
Vimba_6_0/VimbaPython/Source/Tests/real_cam_tests/vimba_test.py
Normal file
@@ -0,0 +1,149 @@
|
||||
"""BSD 2-Clause License
|
||||
|
||||
Copyright (c) 2019, Allied Vision Technologies GmbH
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import ipaddress
|
||||
import struct
|
||||
|
||||
from vimba import *
|
||||
|
||||
|
||||
class CamVimbaTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.vimba = Vimba.get_instance()
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_context_entry_exit(self):
|
||||
# Expected Behavior:
|
||||
# On entering the context features, cameras and interfaces shall
|
||||
# be detected and after leaving the context, everything should be reverted.
|
||||
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_features)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
|
||||
with self.vimba:
|
||||
self.assertNotEqual(self.vimba.get_all_features(), ())
|
||||
self.assertNotEqual(self.vimba.get_all_interfaces(), ())
|
||||
self.assertNotEqual(self.vimba.get_all_cameras(), ())
|
||||
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_features)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
|
||||
def test_get_all_interfaces(self):
|
||||
# Expected Behavior: get_all_interfaces() must raise an RuntimeError in closed state and
|
||||
# be non-empty then opened.
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_interfaces)
|
||||
|
||||
with self.vimba:
|
||||
self.assertTrue(self.vimba.get_all_interfaces())
|
||||
|
||||
def test_get_interface_by_id(self):
|
||||
# Expected Behavior: All detected Interfaces must be lookup able by their Id.
|
||||
# If outside of given scope, an error must be returned
|
||||
with self.vimba:
|
||||
ids = [inter.get_id() for inter in self.vimba.get_all_interfaces()]
|
||||
|
||||
for id_ in ids:
|
||||
self.assertNoRaise(self.vimba.get_interface_by_id, id_)
|
||||
|
||||
for id_ in ids:
|
||||
self.assertRaises(RuntimeError, self.vimba.get_interface_by_id, id_)
|
||||
|
||||
def test_get_all_cameras(self):
|
||||
# Expected Behavior: get_all_cameras() must only return camera handles on a open camera.
|
||||
self.assertRaises(RuntimeError, self.vimba.get_all_cameras)
|
||||
|
||||
with self.vimba:
|
||||
self.assertTrue(self.vimba.get_all_cameras())
|
||||
|
||||
def test_get_camera_by_id(self):
|
||||
# Expected Behavior: Lookup of test camera must not fail after system opening
|
||||
camera_id = self.get_test_camera_id()
|
||||
|
||||
with self.vimba:
|
||||
self.assertNoRaise(self.vimba.get_camera_by_id, camera_id)
|
||||
|
||||
def test_get_camera_by_ip(self):
|
||||
# Expected Behavior: get_camera_by_id() must work with a valid ipv4 address.
|
||||
# A with lookup of an invalid ipv4 address (no Camera attached)
|
||||
# must raise a VimbaCameraError, a lookup with an ipv6 address must raise a
|
||||
# VimbaCameraError in general (VimbaC doesn't support ipv6)
|
||||
with self.vimba:
|
||||
# Verify that the Test Camera is a GigE - Camera
|
||||
cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
inter = self.vimba.get_interface_by_id(cam.get_interface_id())
|
||||
|
||||
if inter.get_type() != InterfaceType.Ethernet:
|
||||
raise self.skipTest('Test requires GigE - Camera.')
|
||||
|
||||
# Lookup test cameras IP address.
|
||||
with cam:
|
||||
ip_as_number = cam.get_feature_by_name('GevCurrentIPAddress').get()
|
||||
|
||||
# Swap byte order, the raw value does not seem to follow network byte order.
|
||||
ip_as_number = struct.pack('<L', ip_as_number)
|
||||
|
||||
# Verify that lookup with IPv4 Address returns the same Camera Object
|
||||
ip_addr = str(ipaddress.IPv4Address(ip_as_number))
|
||||
self.assertEqual(self.vimba.get_camera_by_id(ip_addr), cam)
|
||||
|
||||
# Verify that a lookup with an invalid IPv4 Address raises a VimbaCameraError
|
||||
ip_addr = str(ipaddress.IPv4Address('127.0.0.1'))
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, ip_addr)
|
||||
|
||||
# Verify that a lookup with an IPv6 Address raises a VimbaCameraError
|
||||
ip_addr = str(ipaddress.IPv6Address('FD00::DEAD:BEEF'))
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, ip_addr)
|
||||
|
||||
def test_get_camera_by_mac(self):
|
||||
# Expected Behavior: get_feature_by_id must be usable with a given MAC Address.
|
||||
with self.vimba:
|
||||
# Verify that the Test Camera is a GigE - Camera
|
||||
cam = self.vimba.get_camera_by_id(self.get_test_camera_id())
|
||||
inter = self.vimba.get_interface_by_id(cam.get_interface_id())
|
||||
|
||||
if inter.get_type() != InterfaceType.Ethernet:
|
||||
raise self.skipTest('Test requires GigE - Camera.')
|
||||
|
||||
# Lookup test cameras MAC Address.
|
||||
with cam:
|
||||
# Construct MAC Address from raw value.
|
||||
mac_as_number = cam.get_feature_by_name('GevDeviceMACAddress').get()
|
||||
|
||||
mac_as_bytes = mac_as_number.to_bytes(6, byteorder='big')
|
||||
mac_as_str = ''.join(format(s, '02x') for s in mac_as_bytes).upper()
|
||||
|
||||
# Verify that lookup with MAC Address returns the same Camera Object
|
||||
self.assertEqual(self.vimba.get_camera_by_id(mac_as_str), cam)
|
||||
|
||||
# Verify that a lookup with an invalid MAC Address raises a VimbaCameraError
|
||||
invalid_mac = 'ffffffff'
|
||||
self.assertRaises(VimbaCameraError, self.vimba.get_camera_by_id, invalid_mac)
|
||||
Reference in New Issue
Block a user