Skip to content

Commit

Permalink
Merge pull request #50 from aliddell/sleep-during-inspection
Browse files Browse the repository at this point in the history
Update the reader's tail to its position if no data is mapped
  • Loading branch information
nclack authored Aug 20, 2024
2 parents a5bb73d + 7d2bcc7 commit 8e3e995
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 9 deletions.
17 changes: 8 additions & 9 deletions acquire-video-runtime/src/runtime/channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,18 +191,17 @@ channel_read_map(struct channel* self, struct channel_reader* reader)
reader->cycle = *cycle + 1;
}

// Even if nothing is available on the channel, we still need to advance
// this reader's position & cycle bookmarks to the position & cycle of the
// writer's head. Normally this would happen in channel_read_unmap(), but
// because no data is available, we do not set the reader's state to Mapped
// here. A call to channel_read_unmap() would return early and not advance
// the reader's bookmarks in that case, so we need to do it here.
if (!nbytes) {
goto AdvanceToWriterHead;
// If nothing is available to read, we still need to advance this
// reader's position & cycle bookmarks to the beginning of the queue and
// the writer's cycle, respectively.
out = 0;
*pos = 0;
*cycle = self->cycle;
} else {
reader->state = ChannelState_Mapped;
}

reader->state = ChannelState_Mapped;

Finalize:
lock_release(&self->lock);
return (struct slice){ .beg = out, .end = out + nbytes };
Expand Down
1 change: 1 addition & 0 deletions acquire-video-runtime/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ else ()
filter-video-average
repeat-start-no-monitor
aligned-videoframe-pointers
sleep-while-inspecting
)

foreach (name ${tests})
Expand Down
178 changes: 178 additions & 0 deletions acquire-video-runtime/tests/sleep-while-inspecting.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
/// @file sleep-while-inspecting.cpp
/// Test that uninspected regions will not be overwritten by the runtime.

#include "acquire.h"
#include "device/hal/device.manager.h"
#include "device/props/components.h"
#include "platform.h"
#include "logger.h"

#include <cstdio>
#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);
}

static size_t
bytes_of_frame(const VideoFrame* frame)
{
return sizeof(*frame) + bytes_of_image(&frame->shape);
}

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

void
configure(AcquireRuntime* runtime)
{
CHECK(runtime);

const DeviceManager* dm = acquire_device_manager(runtime);
CHECK(dm);

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

DEVOK(device_manager_select(dm,
DeviceKind_Camera,
SIZED("simulated.*empty.*") - 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 }, 0);

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_u12;
props.video[0].camera.settings.shape = {
.x = 8192,
.y = 8192,
};
props.video[0].max_frame_count = 20;
props.video[0].camera.settings.exposure_time_us = 1e5;

OK(acquire_configure(runtime, &props));
storage_properties_destroy(&props.video[0].storage.settings);
}

void
acquire(AcquireRuntime* runtime)
{
CHECK(runtime);

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

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

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, 1000.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));
}

int
main()
{
int retval = 1;
AcquireRuntime* runtime = acquire_init(reporter);

try {
configure(runtime);
acquire(runtime);
retval = 0;
} catch (const std::exception& e) {
ERR("%s", e.what());
} catch (...) {
ERR("unknown error");
}

acquire_shutdown(runtime);
return retval;
}

0 comments on commit 8e3e995

Please sign in to comment.