Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for ORCA Flash #104

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
60 changes: 57 additions & 3 deletions .github/workflows/test_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,60 @@ env:
BUILD_TYPE: Release

jobs:
test:
runs-on: [ self-hosted, dcam ]
test-fusion:
name: Test on ORCA Fusion
runs-on:
- self-hosted
- dcam
- CP15440-20UP
permissions:
actions: write

steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.10.0
with:
access_token: ${{ github.token }}

- name: Enable long paths
run: |
git config --global core.longpaths true
shell: pwsh

- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
ref: ${{ github.event.pull_request.head.sha }}

- name: Get CMake 3.24
uses: lukka/get-cmake@latest
with:
useCloudCache: false
useLocalCache: true
cmakeVersion: 3.24.3

- name: Install MSVC
uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64_x86

- name: Configure
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}

- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -C ${{env.BUILD_TYPE}} -L acquire-driver-hdcam --output-on-failure

test-flash:
name: Test on ORCA Flash
runs-on:
- self-hosted
- dcam
- C13440-20C
permissions:
actions: write

Expand Down Expand Up @@ -59,7 +111,9 @@ jobs:
merge:
name: Automerge
runs-on: "ubuntu-latest"
needs: test
needs:
- test-fusion
- test-flash
if: ${{ github.actor == 'dependabot[bot]' }}
steps:
- name: Checkout PR
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Driver builds as an OSX universal binary.

### Added

- Support for ORCA-Flash4.0 V3.

## [0.1.6](https://github.com/acquire-project/acquire-driver-hdcam/compare/v0.1.5...v0.1.6) - 2023-08-15

- Fixes a bug where the output trigger source property was set when it shouldn't be.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ This is an Acquire Driver that exposes Hamamatsu cameras via the [DCAM-SDK][].
### Camera

- **Hamamatsu CP15440-20UP** Orca Fusion BT
- **Hamamatsu C13440-20C** Orca Flash 4.0 V3

[DCAM-SDK]: https://dcam-api.com/sdk-download/
4 changes: 3 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ else()
#
set(tests
list-devices
orca-fusion-one-video-stream
orca-flash-one-video-stream
orca-flash-check
abort-finite-acquisition
dcam-check
dcam-list-triggers
dcam-reset-on-fail
one-video-stream
set-output-trigger
set-roi
)
Expand Down
108 changes: 108 additions & 0 deletions tests/orca-flash-check.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "acquire.h"
#include "platform.h"
#include "device/hal/device.manager.h"
#include "logger.h"

#include <cstdio>

#define L (aq_logger)
#define LOG(...) L(0, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
#define ERR(...) L(1, __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
#define CHECK(e) \
do { \
if (!(e)) { \
ERR("Expression evaluated as false: " #e); \
goto Error; \
} \
} while (0)
#define DEVOK(e) CHECK(Device_Ok == (e))
#define OK(e) CHECK(AcquireStatus_Ok == (e))

#define countof(e) (sizeof(e) / sizeof(*(e)))

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);
}

int
main()
{

int ecode = 1;
AcquireRuntime* runtime = 0;
AcquireProperties props = {};

AcquirePropertyMetadata meta = { 0 };

CHECK(runtime = acquire_init(reporter));
OK(acquire_get_configuration(runtime, &props));

// Select devices
{
const DeviceManager* dm;
#define SIZED(s) s, sizeof(s) - 1
CHECK(dm = acquire_device_manager(runtime));
DEVOK(device_manager_select(dm,
DeviceKind_Camera,
SIZED("Hamamatsu C13440-20C.*"),
&props.video[0].camera.identifier));
DEVOK(device_manager_select(dm,
DeviceKind_Storage,
SIZED("Trash"),
&props.video[0].storage.identifier));
#undef SIZED
}

// Configure
{
props.video[0].max_frame_count = 1;
props.video[0].frame_average_count = 0;
props.video[0].camera.settings.pixel_type = SampleType_u16;
props.video[0].camera.settings.shape = { .x = 640, .y = 480 };
OK(acquire_configure(runtime, &props));
}
OK(acquire_get_configuration_metadata(runtime, &meta));
{
const auto* info = &meta.video[0].camera.digital_lines;
for (int i = 0; i < info->line_count; ++i)
LOG("Digital line %d: %s", i, info->names[i]);
}

// Run
{
OK(acquire_start(runtime));
clock_sleep_ms(0, 1000);
OK(acquire_stop(runtime));
}

#if 0
// Check acquired data
{
struct VideoFrame* frames;
size_t bytes_of_frames;
OK(acquire_map_read(runtime, &frames, &bytes_of_frames));
CHECK(frames);
CHECK(bytes_of_frames == 640 * 480 * 2);
}
#endif

ecode = 0;
Finalize:
acquire_shutdown(runtime);
return ecode;
Error:
ecode = 1;
goto Finalize;
}
161 changes: 161 additions & 0 deletions tests/orca-flash-one-video-stream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#include "acquire.h"
#include "device/hal/device.manager.h"
#include "platform.h"
#include "logger.h"

#include <cstdio>
#include <exception>
#include <stdexcept>

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)

#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))

int
main()
{

auto runtime = acquire_init(reporter);
try {
auto dm = acquire_device_manager(runtime);
CHECK(runtime);
CHECK(dm);

AcquireProperties props = {};
OK(acquire_get_configuration(runtime, &props));

DEVOK(device_manager_select(dm,
DeviceKind_Camera,
SIZED("Hamamatsu C13440-20C.*") - 1,
&props.video[0].camera.identifier));
DEVOK(device_manager_select(dm,
DeviceKind_Storage,
SIZED("tiff") - 1,
&props.video[0].storage.identifier));

storage_properties_init(
&props.video[0].storage.settings, 0, SIZED("out.tif"), 0, 0, { 0 });

props.video[0].camera.settings.readout_direction = Direction_Forward;
OK(acquire_configure(runtime, &props));

AcquirePropertyMetadata metadata = { 0 };
OK(acquire_get_configuration_metadata(runtime, &metadata));

props.video[0].camera.settings.binning = 1;
props.video[0].camera.settings.pixel_type = SampleType_u16;
props.video[0].camera.settings.shape = {
.x = (uint32_t)metadata.video[0].camera.shape.x.high,
.y = (uint32_t)metadata.video[0].camera.shape.y.high,
};
props.video[0].camera.settings.exposure_time_us = 1e4;
props.video[0].max_frame_count = 10;

OK(acquire_configure(runtime, &props));

CHECK(props.video[0]
.camera.settings.input_triggers.acquisition_start.enable == 0);
CHECK(
props.video[0].camera.settings.input_triggers.frame_start.enable ==
0);
CHECK(props.video[0].camera.settings.input_triggers.exposure.enable ==
0);

const auto next = [](VideoFrame* cur) -> VideoFrame* {
return (VideoFrame*)(((uint8_t*)cur) + cur->bytes_of_frame);
};

const auto consumed_bytes = [](const VideoFrame* const cur,
const VideoFrame* const end) -> size_t {
return (uint8_t*)end - (uint8_t*)cur;
};

struct clock clock
{};
// expected time to acquire frames + 100%
static double time_limit_ms =
(props.video[0].max_frame_count / 6.0) * 1000.0 * 2.0;
clock_init(&clock);
clock_shift_ms(&clock, time_limit_ms);
OK(acquire_start(runtime));
{
uint64_t nframes = 0;
while (nframes < props.video[0].max_frame_count) {
struct clock throttle
{};
clock_init(&throttle);
EXPECT(clock_cmp_now(&clock) < 0,
"Timeout at %f ms",
clock_toc_ms(&clock) + time_limit_ms);
VideoFrame *beg, *end, *cur;
OK(acquire_map_read(runtime, 0, &beg, &end));
for (cur = beg; cur < end; cur = next(cur)) {
LOG("stream %d counting frame w id %d", 0, cur->frame_id);
CHECK(cur->shape.dims.width ==
props.video[0].camera.settings.shape.x);
CHECK(cur->shape.dims.height ==
props.video[0].camera.settings.shape.y);
++nframes;
}
{
uint32_t n = (uint32_t)consumed_bytes(beg, end);
OK(acquire_unmap_read(runtime, 0, n));
if (n)
LOG("stream %d consumed bytes %d", 0, n);
}
clock_sleep_ms(&throttle, 100.0f);

LOG("stream %d nframes %d. remaining time %f s",
0,
nframes,
-1e-3 * clock_toc_ms(&clock));
}

CHECK(nframes == props.video[0].max_frame_count);
}

OK(acquire_stop(runtime));
OK(acquire_shutdown(runtime));
return 0;
} catch (const std::exception& e) {
ERR("Exception: %s", e.what());
} catch (...) {
ERR("Exception: (unknown)");
}
if (runtime)
acquire_shutdown(runtime);
return 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ main()

DEVOK(device_manager_select(dm,
DeviceKind_Camera,
SIZED("Hamamatsu.*") - 1,
SIZED("Hamamatsu C15440-20UP.*") - 1,
&props.video[0].camera.identifier));
DEVOK(device_manager_select(dm,
DeviceKind_Storage,
Expand Down
Loading