From 85a5d90a857ce5b272d77dc09553e653cb709a5b Mon Sep 17 00:00:00 2001 From: Alan Liddell Date: Tue, 16 Apr 2024 12:21:28 -0400 Subject: [PATCH] Update `StorageProperties` for S3 support (#41) * Change StorageProperties::filename field to StorageProperties::uri. * Add `s3_is_supported` field to StoragePropertyMetadata. * Support file:// URI scheme. * Include * Validate filename only. * Set URI without file:// prefix. * Use `storage_properties_copy` * Validate URI str and nbytes. * Add access_key_id and secret_access_key to StorageProperties. * Update changelog. * Fix and test `storage_properties_set_access_key_and_secret`. --- CHANGELOG.md | 6 + README.md | 2 +- .../device/props/storage.c | 118 +++++++-- .../device/props/storage.h | 53 ++-- acquire-core-libs/tests/unit-tests.cpp | 2 + acquire-driver-common/src/storage/raw.c | 21 +- .../src/storage/side-by-side-tiff.cpp | 32 ++- acquire-driver-common/src/storage/tiff.cpp | 16 +- .../tests/devkit/storage-get-meta.cpp | 1 + .../tests/integration/CMakeLists.txt | 1 + .../integration/can-set-with-file-uri.cpp | 233 ++++++++++++++++++ .../integration/switch-storage-identifier.cpp | 8 +- .../integration/write-side-by-side-tiff.cpp | 5 +- .../tests/change-file-name.cpp | 2 +- 14 files changed, 434 insertions(+), 66 deletions(-) create mode 100644 acquire-driver-common/tests/integration/can-set-with-file-uri.cpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 04611f7..8093e34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Users can specify access key ID and secret access key for S3 storage in `StorageProperties`. + ### Fixed - A bug where changing device identifiers for the storage device was not being handled correctly. @@ -16,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `reserve_image_shape` is now called in `acquire_configure` rather than `acquire_start`. - Users can now specify the names, ordering, and number of acquisition dimensions. +- The `StorageProperties::filename` field is now `StorageProperties::uri`. +- Files can be specified by URI with an optional `file://` prefix. ## 0.2.0 - 2024-01-05 diff --git a/README.md b/README.md index 92fb96b..17ed016 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ This is an Acquire Driver that exposes commonly used devices. - **tiff** - Streams to a [bigtiff] file. Metadata is stored in the `ImageDescription` tag for each frame as a `json` string. - **tiff-json** - Stores the video stream in a *bigtiff* (as above) and stores metadata in a `json` file. Both are - located in a folder identified by the `filename` property. + located in a folder identified by the `uri` property. - **Trash** - Writes nothing. Discards incoming data. [bigtiff]: http://bigtiff.org/ diff --git a/acquire-core-libs/src/acquire-device-properties/device/props/storage.c b/acquire-core-libs/src/acquire-device-properties/device/props/storage.c index 82caa7f..d43db6d 100644 --- a/acquire-core-libs/src/acquire-device-properties/device/props/storage.c +++ b/acquire-core-libs/src/acquire-device-properties/device/props/storage.c @@ -160,14 +160,14 @@ Error:; } int -storage_properties_set_filename(struct StorageProperties* out, - const char* filename, - size_t bytes_of_filename) +storage_properties_set_uri(struct StorageProperties* out, + const char* uri, + size_t bytes_of_uri) { const struct String s = { .is_ref = 1, - .nbytes = bytes_of_filename, - .str = (char*)filename }; - return copy_string(&out->filename, &s); + .nbytes = bytes_of_uri, + .str = (char*)uri }; + return copy_string(&out->uri, &s); } int @@ -181,6 +181,26 @@ storage_properties_set_external_metadata(struct StorageProperties* out, return copy_string(&out->external_metadata_json, &s); } +int +storage_properties_set_access_key_and_secret(struct StorageProperties* out, + const char* access_key_id, + size_t bytes_of_access_key_id, + const char* secret_access_key, + size_t bytes_of_secret_access_key) +{ + const struct String s = { .is_ref = 1, + .nbytes = bytes_of_access_key_id, + .str = (char*)access_key_id }; + CHECK(copy_string(&out->access_key_id, &s)); + + const struct String t = { .is_ref = 1, + .nbytes = bytes_of_secret_access_key, + .str = (char*)secret_access_key }; + return copy_string(&out->secret_access_key, &t); +Error: + return 0; +} + int storage_properties_set_dimension(struct StorageProperties* out, int index, @@ -238,8 +258,8 @@ storage_properties_set_enable_multiscale(struct StorageProperties* out, int storage_properties_init(struct StorageProperties* out, uint32_t first_frame_id, - const char* filename, - size_t bytes_of_filename, + const char* uri, + size_t bytes_of_uri, const char* metadata, size_t bytes_of_metadata, struct PixelScale pixel_scale_um, @@ -247,7 +267,7 @@ storage_properties_init(struct StorageProperties* out, { // Allocate and copy filename memset(out, 0, sizeof(*out)); // NOLINT - CHECK(storage_properties_set_filename(out, filename, bytes_of_filename)); + CHECK(storage_properties_set_uri(out, uri, bytes_of_uri)); // Set external metadata CHECK(storage_properties_set_external_metadata( @@ -272,22 +292,37 @@ storage_properties_copy(struct StorageProperties* dst, { // 1. Copy everything except the strings { - struct String tmp_fname, tmp_meta; - memcpy(&tmp_fname, &dst->filename, sizeof(struct String)); // NOLINT - memcpy(&tmp_meta, // NOLINT + struct String tmp_uri, tmp_meta, tmp_access_key, tmp_secret_key; + memcpy(&tmp_uri, &dst->uri, sizeof(struct String)); // NOLINT + memcpy(&tmp_meta, // NOLINT &dst->external_metadata_json, sizeof(struct String)); - memcpy(dst, src, sizeof(*dst)); // NOLINT - memcpy(&dst->filename, &tmp_fname, sizeof(struct String)); // NOLINT - memcpy(&dst->external_metadata_json, // NOLINT + memcpy(&tmp_access_key, + &dst->access_key_id, + sizeof(struct String)); // NOLINT + memcpy(&tmp_secret_key, + &dst->secret_access_key, + sizeof(struct String)); // NOLINT + + memcpy(dst, src, sizeof(*dst)); // NOLINT + memcpy(&dst->uri, &tmp_uri, sizeof(struct String)); // NOLINT + memcpy(&dst->external_metadata_json, // NOLINT &tmp_meta, sizeof(struct String)); + memcpy(&dst->access_key_id, + &tmp_access_key, + sizeof(struct String)); // NOLINT + memcpy(&dst->secret_access_key, + &tmp_secret_key, + sizeof(struct String)); // NOLINT } // 2. Reallocate and copy the Strings - CHECK(copy_string(&dst->filename, &src->filename)); + CHECK(copy_string(&dst->uri, &src->uri)); CHECK( copy_string(&dst->external_metadata_json, &src->external_metadata_json)); + CHECK(copy_string(&dst->access_key_id, &src->access_key_id)); + CHECK(copy_string(&dst->secret_access_key, &src->secret_access_key)); // 3. Copy the dimensions if (src->acquisition_dimensions.data) { @@ -309,8 +344,10 @@ storage_properties_copy(struct StorageProperties* dst, void storage_properties_destroy(struct StorageProperties* self) { - struct String* const strings[] = { &self->filename, - &self->external_metadata_json }; + struct String* const strings[] = { &self->uri, + &self->external_metadata_json, + &self->access_key_id, + &self->secret_access_key }; for (int i = 0; i < countof(strings); ++i) { if (strings[i]->is_ref == 0 && strings[i]->str) { free(strings[i]->str); @@ -348,9 +385,9 @@ unit_test__storage__storage_property_string_check() sizeof(metadata), pixel_scale_um, 0)); - CHECK(props.filename.str[props.filename.nbytes - 1] == '\0'); - ASSERT_EQ(int, "%d", props.filename.nbytes, sizeof(filename)); - ASSERT_EQ(int, "%d", props.filename.is_ref, 0); + CHECK(props.uri.str[props.uri.nbytes - 1] == '\0'); + ASSERT_EQ(int, "%d", props.uri.nbytes, sizeof(filename)); + ASSERT_EQ(int, "%d", props.uri.is_ref, 0); CHECK(props.external_metadata_json .str[props.external_metadata_json.nbytes - 1] == '\0'); @@ -375,9 +412,9 @@ unit_test__storage__storage_property_string_check() sizeof(metadata), pixel_scale_um, 0)); - CHECK(src.filename.str[src.filename.nbytes - 1] == '\0'); - CHECK(src.filename.nbytes == sizeof(filename)); - CHECK(src.filename.is_ref == 0); + CHECK(src.uri.str[src.uri.nbytes - 1] == '\0'); + CHECK(src.uri.nbytes == sizeof(filename)); + CHECK(src.uri.is_ref == 0); CHECK(src.pixel_scale_um.x == 1); CHECK(src.pixel_scale_um.y == 2); @@ -388,9 +425,9 @@ unit_test__storage__storage_property_string_check() CHECK(storage_properties_copy(&props, &src)); storage_properties_destroy(&src); - CHECK(props.filename.str[props.filename.nbytes - 1] == '\0'); - CHECK(props.filename.nbytes == sizeof(filename)); - CHECK(props.filename.is_ref == 0); + CHECK(props.uri.str[props.uri.nbytes - 1] == '\0'); + CHECK(props.uri.nbytes == sizeof(filename)); + CHECK(props.uri.is_ref == 0); CHECK(props.external_metadata_json .str[props.external_metadata_json.nbytes - 1] == '\0'); @@ -505,6 +542,33 @@ unit_test__storage__copy_string() return 0; } +int +unit_test__storage_properties_set_access_key_and_secret() +{ + struct StorageProperties props = { 0 }; + const char access_key_id[] = "access_key_id"; + const char secret_access_key[] = "secret_access_key"; + + CHECK( + storage_properties_set_access_key_and_secret(&props, + access_key_id, + sizeof(access_key_id), + secret_access_key, + sizeof(secret_access_key))); + + CHECK(0 == strcmp(props.access_key_id.str, access_key_id)); + CHECK(props.access_key_id.nbytes == sizeof(access_key_id)); + CHECK(0 == props.access_key_id.is_ref); + + CHECK(0 == strcmp(props.secret_access_key.str, secret_access_key)); + CHECK(props.secret_access_key.nbytes == sizeof(secret_access_key)); + CHECK(0 == props.secret_access_key.is_ref); + + return 1; +Error: + return 0; +} + int unit_test__dimension_init() { diff --git a/acquire-core-libs/src/acquire-device-properties/device/props/storage.h b/acquire-core-libs/src/acquire-device-properties/device/props/storage.h index 5f4b4c4..8133a28 100644 --- a/acquire-core-libs/src/acquire-device-properties/device/props/storage.h +++ b/acquire-core-libs/src/acquire-device-properties/device/props/storage.h @@ -42,8 +42,11 @@ extern "C" /// Properties for a storage driver. struct StorageProperties { - struct String filename; + struct String uri; struct String external_metadata_json; + struct String access_key_id; + struct String secret_access_key; + uint32_t first_frame_id; struct PixelScale pixel_scale_um; @@ -68,6 +71,7 @@ extern "C" uint8_t chunking_is_supported; uint8_t sharding_is_supported; uint8_t multiscale_is_supported; + uint8_t s3_is_supported; }; /// Initializes StorageProperties, allocating string storage on the heap @@ -76,10 +80,10 @@ extern "C" /// @param[out] out The constructed StorageProperties object. /// @param[in] first_frame_id (unused; aiming for future file rollover /// support - /// @param[in] filename A c-style null-terminated string. The file to create - /// for streaming. - /// @param[in] bytes_of_filename Number of bytes in the `filename` buffer - /// including the terminating null. + /// @param[in] uri A c-style null-terminated string. The file to create + /// for streaming. + /// @param[in] bytes_of_uri Number of bytes in the `uri` buffer, + /// including the terminating null. /// @param[in] metadata A c-style null-terminated string. Metadata string /// to save along side the created file. /// @param[in] bytes_of_metadata Number of bytes in the `metadata` buffer @@ -90,8 +94,8 @@ extern "C" /// to zero. int storage_properties_init(struct StorageProperties* out, uint32_t first_frame_id, - const char* filename, - size_t bytes_of_filename, + const char* uri, + size_t bytes_of_uri, const char* metadata, size_t bytes_of_metadata, struct PixelScale pixel_scale_um, @@ -105,28 +109,47 @@ extern "C" int storage_properties_copy(struct StorageProperties* dst, const struct StorageProperties* src); - /// @brief Set the filename string in `out`. + /// @brief Set the uri string in `out`. /// Copies the string into storage owned by the properties struct. /// @returns 1 on success, otherwise 0 /// @param[in,out] out The storage properties to change. - /// @param[in] filename pointer to the beginning of the filename buffer. - /// @param[in] bytes_of_filename the number of bytes in the filename buffer. - /// Should include the terminating NULL. - int storage_properties_set_filename(struct StorageProperties* out, - const char* filename, - size_t bytes_of_filename); + /// @param[in] uri Pointer to the beginning of the uri buffer. + /// @param[in] bytes_of_uri The number of bytes in the uri buffer. + /// Should include the terminating NULL. + int storage_properties_set_uri(struct StorageProperties* out, + const char* uri, + size_t bytes_of_uri); /// @brief Set the metadata string in `out`. /// Copies the string into storage owned by the properties struct. /// @returns 1 on success, otherwise 0 /// @param[in,out] out The storage properties to change. /// @param[in] metadata pointer to the beginning of the metadata buffer. - /// @param[in] bytes_of_filename the number of bytes in the metadata buffer. + /// @param[in] bytes_of_metadata the number of bytes in the metadata buffer. /// Should include the terminating NULL. int storage_properties_set_external_metadata(struct StorageProperties* out, const char* metadata, size_t bytes_of_metadata); + /// @brief Set the access key id string in `out`. + /// Copies the string into storage owned by the properties struct. + /// @returns 1 on success, otherwise 0 + /// @param[in,out] out The storage properties to change. + /// @param[in] access_key_id Pointer to the beginning of the access key id + /// buffer. + /// @param[in] bytes_of_access_key_id The number of bytes in the access key + /// id. + /// @param[in] secret_access_key Pointer to the beginning of the secret + /// access key buffer. + /// @param[in] bytes_of_secret_access_key The number of bytes in the secret + /// access key. + int storage_properties_set_access_key_and_secret( + struct StorageProperties* out, + const char* access_key_id, + size_t bytes_of_access_key_id, + const char* secret_access_key, + size_t bytes_of_secret_access_key); + /// @brief Set the value of the StorageDimension struct at index `index` in /// `out`. /// @param[out] out The StorageProperties struct containing the diff --git a/acquire-core-libs/tests/unit-tests.cpp b/acquire-core-libs/tests/unit-tests.cpp index 78f1d12..02ab050 100644 --- a/acquire-core-libs/tests/unit-tests.cpp +++ b/acquire-core-libs/tests/unit-tests.cpp @@ -70,6 +70,7 @@ extern "C" // device-properties int unit_test__storage__storage_property_string_check(); int unit_test__storage__copy_string(); + int unit_test__storage_properties_set_access_key_and_secret(); int unit_test__dimension_init(); int unit_test__storage_properties_dimensions_init(); int unit_test__storage_properties_dimensions_destroy(); @@ -98,6 +99,7 @@ main() CASE(unit_test__monotonic_clock_increases_monotonically), CASE(unit_test__storage__storage_property_string_check), CASE(unit_test__storage__copy_string), + CASE(unit_test__storage_properties_set_access_key_and_secret), CASE(unit_test__dimension_init), CASE(unit_test__storage_properties_dimensions_init), CASE(unit_test__storage_properties_dimensions_destroy), diff --git a/acquire-driver-common/src/storage/raw.c b/acquire-driver-common/src/storage/raw.c index 62319f1..a20264e 100644 --- a/acquire-driver-common/src/storage/raw.c +++ b/acquire-driver-common/src/storage/raw.c @@ -35,8 +35,15 @@ static enum DeviceState raw_set(struct Storage* self_, const struct StorageProperties* properties) { struct Raw* self = containerof(self_, struct Raw, writer); - const char* filename = properties->filename.str; - const size_t nbytes = properties->filename.nbytes; + CHECK(properties->uri.str); + CHECK(properties->uri.nbytes); + + const size_t offset = strlen(properties->uri.str) >= 7 && + strncmp(properties->uri.str, "file://", 7) == 0 + ? 7 + : 0; + const char* filename = properties->uri.str + offset; + const size_t nbytes = properties->uri.nbytes - offset; // Validate CHECK(file_is_writable(filename, nbytes)); @@ -44,6 +51,11 @@ raw_set(struct Storage* self_, const struct StorageProperties* properties) // copy in the properties CHECK(storage_properties_copy(&self->properties, properties)); + // update the URI if it has a file:// prefix + if (offset) { + storage_properties_set_uri(&self->properties, filename, nbytes); + } + return DeviceState_Armed; Error: return DeviceState_AwaitingConfiguration; @@ -69,9 +81,8 @@ static enum DeviceState raw_start(struct Storage* self_) { struct Raw* self = containerof(self_, struct Raw, writer); - CHECK(file_create(&self->file, - self->properties.filename.str, - self->properties.filename.nbytes)); + CHECK(file_create( + &self->file, self->properties.uri.str, self->properties.uri.nbytes)); LOG("RAW: Frame header size %d bytes", (int)sizeof(struct VideoFrame)); return DeviceState_Running; Error: diff --git a/acquire-driver-common/src/storage/side-by-side-tiff.cpp b/acquire-driver-common/src/storage/side-by-side-tiff.cpp index b9b837e..e0fa238 100644 --- a/acquire-driver-common/src/storage/side-by-side-tiff.cpp +++ b/acquire-driver-common/src/storage/side-by-side-tiff.cpp @@ -17,6 +17,7 @@ #include "logger.h" #include +#include #include #include @@ -51,8 +52,7 @@ struct SideBySideTiff fs::path as_path(const StorageProperties& props) { - return { props.filename.str, - props.filename.str + props.filename.nbytes - 1 }; + return { props.uri.str, props.uri.str + props.uri.nbytes - 1 }; } void @@ -88,8 +88,16 @@ validate(const struct StorageProperties* props) props->external_metadata_json.nbytes); { - fs::path path(props->filename.str, - props->filename.str + props->filename.nbytes); + CHECK(props->uri.str); + CHECK(props->uri.nbytes); + + const size_t offset = strlen(props->uri.str) >= 7 && + strncmp(props->uri.str, "file://", 7) == 0 + ? 7 + : 0; + + fs::path path(props->uri.str + offset, + (props->uri.str + offset) + (props->uri.nbytes - offset)); auto parent_path = path.parent_path(); if (parent_path.empty()) { parent_path = fs::path("."); @@ -110,7 +118,19 @@ side_by_side_tiff_set(struct Storage* self_, struct SideBySideTiff* self = containerof(self_, struct SideBySideTiff, storage); validate(props); - self->props = *props; + CHECK(storage_properties_copy(&self->props, props)); + + const size_t offset = strlen(props->uri.str) >= 7 && + strncmp(props->uri.str, "file://", 7) == 0 + ? 7 + : 0; + + // update the URI if it has a file:// prefix + if (offset) { + const char* filename = props->uri.str + offset; + const size_t nbytes = props->uri.nbytes - offset; + CHECK(storage_properties_set_uri(&self->props, filename, nbytes)); + } } catch (const std::exception& e) { LOGE("Exception: %s\n", e.what()); @@ -190,7 +210,7 @@ side_by_side_tiff_start(struct Storage* self_) noexcept const auto video_path = (path / "data.tif").generic_string(); StorageProperties props{}; storage_properties_copy(&props, &self->props); - props.filename = { + props.uri = { .str = (char*)video_path.c_str(), .nbytes = video_path.length(), .is_ref = 1, diff --git a/acquire-driver-common/src/storage/tiff.cpp b/acquire-driver-common/src/storage/tiff.cpp index e672b96..46858ce 100644 --- a/acquire-driver-common/src/storage/tiff.cpp +++ b/acquire-driver-common/src/storage/tiff.cpp @@ -4,6 +4,7 @@ #include "platform.h" #include +#include #include #include #include @@ -424,10 +425,15 @@ validate_json(const char* str, size_t nbytes) int Tiff::set(const struct StorageProperties* settings) noexcept { - EXPECT(settings->filename.str, "Filename string is NULL."); - EXPECT(settings->filename.nbytes, "Filename string is zero size."); + EXPECT(settings->uri.str, "Filename string is NULL."); + EXPECT(settings->uri.nbytes, "Filename string is zero size."); { - string filename(settings->filename.str); + const size_t offset = strlen(settings->uri.str) >= 7 && + strncmp(settings->uri.str, "file://", 7) == 0 + ? 7 + : 0; + string filename(settings->uri.str + offset, + settings->uri.nbytes - offset); // Validate and copy the filename CHECK(file_is_writable(filename.c_str(), filename.length())); @@ -451,8 +457,8 @@ Tiff::set(const struct StorageProperties* settings) noexcept void Tiff::get(struct StorageProperties* settings) const noexcept { - settings->filename.str = (char*)filename_.c_str(); - settings->filename.nbytes = filename_.size(); + settings->uri.str = (char*)filename_.c_str(); + settings->uri.nbytes = filename_.size(); settings->pixel_scale_um = pixel_scale_um_; } diff --git a/acquire-driver-common/tests/devkit/storage-get-meta.cpp b/acquire-driver-common/tests/devkit/storage-get-meta.cpp index e5ce478..15c8812 100644 --- a/acquire-driver-common/tests/devkit/storage-get-meta.cpp +++ b/acquire-driver-common/tests/devkit/storage-get-meta.cpp @@ -75,6 +75,7 @@ main() CHECK(0 == metadata.chunking_is_supported); CHECK(0 == metadata.sharding_is_supported); CHECK(0 == metadata.multiscale_is_supported); + CHECK(0 == metadata.s3_is_supported); CHECK(Device_Ok == driver_close_device(device)); } diff --git a/acquire-driver-common/tests/integration/CMakeLists.txt b/acquire-driver-common/tests/integration/CMakeLists.txt index 5ddb46a..c1ca5ea 100644 --- a/acquire-driver-common/tests/integration/CMakeLists.txt +++ b/acquire-driver-common/tests/integration/CMakeLists.txt @@ -11,6 +11,7 @@ else () # set(tests abort-while-waiting-for-trigger + can-set-with-file-uri configure-triggering list-digital-lines software-trigger-acquires-single-frames diff --git a/acquire-driver-common/tests/integration/can-set-with-file-uri.cpp b/acquire-driver-common/tests/integration/can-set-with-file-uri.cpp new file mode 100644 index 0000000..755e1b2 --- /dev/null +++ b/acquire-driver-common/tests/integration/can-set-with-file-uri.cpp @@ -0,0 +1,233 @@ +/// @file can-set-with-file-uri.cpp +/// Test that we can use a file:// URI when configuring basic Storage devices. + +#include "acquire.h" +#include "device/hal/device.manager.h" +#include "logger.h" + +#include +#include +#include +#include + +namespace fs = std::filesystem; + +void +reporter(int is_error, + const char* file, + int line, + const char* function, + const char* msg) +{ + fprintf(is_error ? stderr : stdout, + "%s%s(%d) - %s: %s\n", + is_error ? "ERROR " : "", + file, + line, + function, + msg); +} + +/// Helper for passing size static strings as function args. +/// For a function: `f(char*,size_t)` use `f(SIZED("hello"))`. +/// Expands to `f("hello",5)`. +#define SIZED(str) str, sizeof(str) - 1 + +#define L (aq_logger) +#define LOG(...) L(0, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define ERR(...) L(1, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define EXPECT(e, ...) \ + do { \ + if (!(e)) { \ + char buf[1 << 8] = { 0 }; \ + ERR(__VA_ARGS__); \ + snprintf(buf, sizeof(buf) - 1, __VA_ARGS__); \ + throw std::runtime_error(buf); \ + } \ + } while (0) +#define CHECK(e) EXPECT(e, "Expression evaluated as false: %s", #e) +#define DEVOK(e) CHECK(Device_Ok == (e)) +#define OK(e) CHECK(AcquireStatus_Ok == (e)) + +const static uint32_t nframes = 32; + +void +configure_camera(AcquireRuntime* runtime) +{ + CHECK(runtime); + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + auto* dm = acquire_device_manager(runtime); + CHECK(dm); + + DEVOK(device_manager_select(dm, + DeviceKind_Camera, + SIZED(".*empty.*"), + &props.video[0].camera.identifier)); + + props.video[0].camera.settings.binning = 1; + props.video[0].camera.settings.pixel_type = SampleType_u8; + props.video[0].camera.settings.shape = { .x = 64, .y = 48 }; + props.video[0].camera.settings.exposure_time_us = 1e4; + props.video[0].max_frame_count = nframes; + + OK(acquire_configure(runtime, &props)); +} + +void +configure_storage_tiff(AcquireRuntime* runtime, const std::string& filename) +{ + CHECK(runtime); + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + auto* dm = acquire_device_manager(runtime); + CHECK(dm); + + props.video[0].storage = { 0 }; + DEVOK(device_manager_select(dm, + DeviceKind_Storage, + SIZED("tiff"), + &props.video[0].storage.identifier)); + + storage_properties_set_uri( + &props.video[0].storage.settings, filename.c_str(), filename.size() + 1); + + OK(acquire_configure(runtime, &props)); +} + +void +validate_storage_tiff(AcquireRuntime* runtime) +{ + const std::string file_path = TEST ".tif"; + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + CHECK(0 == strncmp(props.video[0].storage.settings.uri.str, + file_path.c_str(), + file_path.size() + 1)); +} + +void +configure_storage_side_by_side_tiff(AcquireRuntime* runtime, + const std::string& filename) +{ + CHECK(runtime); + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + auto* dm = acquire_device_manager(runtime); + CHECK(dm); + + props.video[0].storage = { 0 }; + DEVOK(device_manager_select(dm, + DeviceKind_Storage, + SIZED("tiff-json"), + &props.video[0].storage.identifier)); + + storage_properties_set_uri( + &props.video[0].storage.settings, filename.c_str(), filename.size() + 1); + + OK(acquire_configure(runtime, &props)); +} + +void +validate_storage_side_by_side_tiff(AcquireRuntime* runtime) +{ + const std::string file_path = TEST ".tif"; + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + CHECK(0 == strncmp(props.video[0].storage.settings.uri.str, + file_path.c_str(), + file_path.size() + 1)); +} + +void +configure_storage_raw(AcquireRuntime* runtime, const std::string& filename) +{ + CHECK(runtime); + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + auto* dm = acquire_device_manager(runtime); + CHECK(dm); + + props.video[0].storage = { 0 }; + DEVOK(device_manager_select(dm, + DeviceKind_Storage, + SIZED("Raw"), + &props.video[0].storage.identifier)); + + storage_properties_set_uri(&props.video[0].storage.settings, + filename.c_str(), + filename.size() + 1); + + OK(acquire_configure(runtime, &props)); +} + +void +validate_storage_raw(AcquireRuntime* runtime) +{ + const std::string file_path = TEST ".bin"; + + AcquireProperties props = {}; + OK(acquire_get_configuration(runtime, &props)); + + CHECK(0 == strncmp(props.video[0].storage.settings.uri.str, + file_path.c_str(), + file_path.size() + 1)); +} + +void +acquire(AcquireRuntime* runtime) +{ + CHECK(runtime); + + OK(acquire_start(runtime)); + OK(acquire_stop(runtime)); +} + +int +main() +{ + auto* runtime = acquire_init(reporter); + try { + configure_camera(runtime); + + configure_storage_raw(runtime, TEST ".bin"); + validate_storage_raw(runtime); + + configure_storage_raw(runtime, "file://" TEST ".bin"); + validate_storage_raw(runtime); + + configure_storage_tiff(runtime, TEST ".tif"); + validate_storage_tiff(runtime); + + configure_storage_tiff(runtime, "file://" TEST ".tif"); + validate_storage_tiff(runtime); + + configure_storage_side_by_side_tiff(runtime, TEST ".tif"); + validate_storage_side_by_side_tiff(runtime); + + configure_storage_side_by_side_tiff(runtime, "file://" TEST ".tif"); + validate_storage_side_by_side_tiff(runtime); + + } catch (const std::exception& exc) { + acquire_shutdown(runtime); + return 1; + } catch (...) { + acquire_shutdown(runtime); + return 1; + } + + acquire_shutdown(runtime); + return 0; +} \ No newline at end of file diff --git a/acquire-driver-common/tests/integration/switch-storage-identifier.cpp b/acquire-driver-common/tests/integration/switch-storage-identifier.cpp index 0fe0247..6ed0d79 100644 --- a/acquire-driver-common/tests/integration/switch-storage-identifier.cpp +++ b/acquire-driver-common/tests/integration/switch-storage-identifier.cpp @@ -112,8 +112,8 @@ configure_storage_tiff(AcquireRuntime* runtime) SIZED("tiff"), &props.video[0].storage.identifier)); - storage_properties_set_filename(&props.video[0].storage.settings, - SIZED(TEST ".tif") + 1); + storage_properties_set_uri(&props.video[0].storage.settings, + SIZED(TEST ".tif") + 1); OK(acquire_configure(runtime, &props)); } @@ -150,8 +150,8 @@ configure_storage_raw(AcquireRuntime* runtime) SIZED("Raw"), &props.video[0].storage.identifier)); - storage_properties_set_filename(&props.video[0].storage.settings, - SIZED(TEST ".bin") + 1); + storage_properties_set_uri(&props.video[0].storage.settings, + SIZED(TEST ".bin") + 1); OK(acquire_configure(runtime, &props)); } diff --git a/acquire-driver-common/tests/integration/write-side-by-side-tiff.cpp b/acquire-driver-common/tests/integration/write-side-by-side-tiff.cpp index bf44725..5911125 100644 --- a/acquire-driver-common/tests/integration/write-side-by-side-tiff.cpp +++ b/acquire-driver-common/tests/integration/write-side-by-side-tiff.cpp @@ -1,5 +1,6 @@ /// @file write-side-by-side-tiff.cpp -/// Test that the side-by-side tiff/JSON writer writes a TIFF file and a JSON file. +/// Test that the side-by-side tiff/JSON writer writes a TIFF file and a JSON +/// file. #include "acquire.h" #include "device/hal/device.manager.h" @@ -77,7 +78,7 @@ acquire(AcquireRuntime* runtime, const char* filename) .is_ref = 1, }; - props.video[0].storage.settings.filename = { + props.video[0].storage.settings.uri = { .str = (char*)filename, .nbytes = strlen(filename) + 1, .is_ref = 1, diff --git a/acquire-video-runtime/tests/change-file-name.cpp b/acquire-video-runtime/tests/change-file-name.cpp index 512a829..4335b28 100644 --- a/acquire-video-runtime/tests/change-file-name.cpp +++ b/acquire-video-runtime/tests/change-file-name.cpp @@ -53,7 +53,7 @@ acquire(AcquireRuntime* runtime, struct AcquireProperties* props, const char* filename) { - storage_properties_set_filename( + storage_properties_set_uri( &props->video[0].storage.settings, filename, strlen(filename) + 1); OK(acquire_configure(runtime, props));