Commit 21fceea8 authored by Éric Thiébaut's avatar Éric Thiébaut
Browse files

Re-organize headers for shared cameras

parent 0f7d6eae
......@@ -14,7 +14,7 @@
#include "tao-errors.h"
#include "tao-servers-private.h"
#include "tao-cameras-private.h"
#include "tao-remote-cameras-private.h"
#include "tao-shared-cameras-private.h"
#include "tao-shared-arrays-private.h"
#include <limits.h>
......
......@@ -56,7 +56,7 @@ int main(
}
tao_status status = TAO_OK;
if (status == TAO_OK) {
status = tao_print_camera_information(stdout, &cam->info);
status = tao_camera_info_print(stdout, &cam->info);
}
if (status == TAO_OK) {
status = andor_print_supported_encodings(stdout, andor_get_device(cam));
......
......@@ -58,7 +58,7 @@ int main(
tao_report_error();
return EXIT_FAILURE;
}
tao_print_camera_information(stdout, &cam->info);
tao_camera_info_print(stdout, &cam->info);
andor_print_supported_encodings(stdout, andor_get_device(cam));
// Measure time taken for updating all the configuration and compare to
......@@ -91,7 +91,7 @@ int main(
return EXIT_FAILURE;
}
fprintf(stdout, "\n");
tao_print_camera_information(stdout, &cam->info);
tao_camera_info_print(stdout, &cam->info);
tao_get_camera_configuration(cam, &cfg, false);
// Allocate an array to save some images.
......
......@@ -68,8 +68,6 @@ include_HEADERS = \
tao-misc.h \
tao-options.h \
tao-preprocessing.h \
tao-remote-cameras.h \
tao-remote-cameras-private.h \
tao-remote-mirrors.h \
tao-remote-mirrors-private.h \
tao-remote-objects.h \
......@@ -80,6 +78,8 @@ include_HEADERS = \
tao-servers-private.h \
tao-shared-arrays.h \
tao-shared-arrays-private.h \
tao-shared-cameras.h \
tao-shared-cameras-private.h \
tao-shared-memory.h \
tao-shared-objects.h \
tao-shared-objects-private.h \
......@@ -106,6 +106,7 @@ libtao_la_SOURCES = \
preprocessing.c \
semaphores.c \
shared-arrays.c \
shared-cameras.c \
shared-objects.c \
threadpools.c \
utils.c
......
// cameras.c -
//
// Management of (shared) cameras in TAO.
// Unified API for camera devices in TAO.
//
//-----------------------------------------------------------------------------
//
......@@ -10,7 +10,7 @@
// Copyright (C) 2018-2022, Éric Thiébaut.
#include "tao-cameras-private.h"
#include "tao-remote-cameras-private.h"
#include "tao-shared-cameras-private.h"
#include "tao-shared-arrays-private.h"
#include "tao-errors.h"
#include "tao-generic.h"
......@@ -21,8 +21,6 @@
#include <math.h>
#include <string.h>
#define FRAMEGRABBER_TRY_LOCK 0
static inline void fatal_error(
const char* func,
int code)
......@@ -124,10 +122,12 @@ static inline void get_monotonic_time(
}
}
static void initialize_camera_info(
void tao_camera_info_initialize(
tao_camera_info* info)
{
if (info == NULL) {
return;
}
memset(info, 0, sizeof(tao_camera_info));
info->sensorwidth = 1;
info->sensorheight = 1;
......@@ -236,7 +236,7 @@ tao_camera* tao_create_camera(
}
cam->ops = ops;
cam->ctx = ctx;
initialize_camera_info(&cam->info);
tao_camera_info_initialize(&cam->info);
cam->runlevel = 0;
cam->info.state = TAO_STATE_INITIALIZING;
if (cam->ops->initialize(cam) != TAO_OK) {
......@@ -728,7 +728,7 @@ tao_status tao_print_camera_configuration(
return TAO_OK;
}
tao_status tao_print_camera_information(
tao_status tao_camera_info_print(
FILE* out,
const tao_camera_info* inf)
{
......@@ -764,351 +764,3 @@ tao_status tao_print_camera_information(
}
return TAO_OK;
}
//-----------------------------------------------------------------------------
// FRAME-GRABBERS
tao_status tao_destroy_framegrabber(
tao_framegrabber* fg)
{
tao_status status = TAO_OK;
if (fg != NULL) {
if (fg->camera != NULL) {
tao_shared_camera* cam = fg->camera;
fg->camera = NULL;
if (tao_shared_camera_detach(cam) != TAO_OK) {
status = TAO_ERROR;
}
}
if (fg->locked != NULL) {
tao_shared_array* arr = fg->locked;
fg->locked = NULL;
if (tao_shared_array_unlock(arr) != TAO_OK) {
status = TAO_ERROR;
}
}
if (fg->list != NULL) {
tao_shared_array** list = fg->list;
for (int i = 0; i < fg->nbufs; ++i) {
tao_shared_array* arr = list[i];
list[i] = NULL;
if (arr != NULL &&
tao_shared_array_detach(arr) != TAO_OK) {
status = TAO_ERROR;
}
}
fg->list = NULL;
free(list);
}
free(fg);
}
return status;
}
tao_framegrabber* tao_create_framegrabber(
const char* owner,
int nbufs,
unsigned flags)
{
long len = TAO_STRLEN(owner);
if (len < 1) {
tao_store_error(__func__, TAO_BAD_NAME);
return NULL;
}
if (nbufs < 2) {
tao_store_error(__func__, TAO_BAD_ARGUMENT);
return NULL;
}
tao_framegrabber* fg = TAO_NEW(1, tao_framegrabber);
if (fg == NULL) {
return NULL;
}
fg->flags = flags;
fg->list = TAO_NEW(nbufs, tao_shared_array*);
if (fg->list == NULL) {
tao_destroy_framegrabber(fg);
return NULL;
}
tao_forced_store(&fg->nbufs, nbufs);
fg->serial = 0;
tao_shared_camera* cam = (tao_shared_camera*)tao_rwlocked_object_create(
TAO_SHARED_CAMERA, sizeof(tao_shared_camera), flags);
if (cam == NULL) {
tao_destroy_framegrabber(fg);
return NULL;
}
for (long i = 0; i < len; ++i) {
((char*)cam->owner)[i] = owner[i];
}
((char*)cam->owner)[len] = '\0';
fg->camera = cam;
initialize_camera_info(&cam->info);
tao_forced_store(&cam->nbufs, nbufs);
cam->serial = fg->serial;
cam->lastframe = TAO_BAD_SHMID;
cam->nextframe = TAO_BAD_SHMID;
return fg;
}
tao_shared_camera* tao_get_framegrabber_shared_camera(
tao_framegrabber* fg)
{
return (fg != NULL ? fg->camera : NULL);
}
tao_shared_array* tao_get_framegrabber_buffer(
tao_framegrabber* fg)
{
return (fg != NULL ? fg->locked : NULL);
}
static tao_shared_array* allocate_frame(
tao_shared_camera* cam,
unsigned flags)
{
tao_shared_array* arr;
if (cam->info.config.weighted == false) {
arr = tao_shared_array_create_2d(cam->info.config.pixeltype,
cam->info.config.roi.width,
cam->info.config.roi.height,
flags);
} else {
arr = tao_shared_array_create_3d(cam->info.config.pixeltype,
cam->info.config.roi.width,
cam->info.config.roi.height,
2, flags);
}
return arr;
}
// Yield whether shared array `arr` is suitable to store the frame data for
// shared camera `cam`. The shared camera should be locked by the caller but
// the shared array may not be locked as all checked parameters are, in
// principle, read-only by every one. This may be used to avoid the overheads
// of locking the array.
static inline int is_suitable(
const tao_shared_array* arr,
const tao_shared_camera* cam)
{
return (TAO_SHARED_ARRAY_SHMID(arr) != cam->lastframe &&
arr->eltype == cam->info.config.pixeltype &&
arr->dims[0] == cam->info.config.roi.width &&
arr->dims[1] == cam->info.config.roi.height &&
(cam->info.config.weighted
? (arr->ndims == 3 && arr->dims[2] == 2)
: (arr->ndims == 2)));
}
static inline tao_shared_array* fetch_next_frame(
tao_framegrabber* fg)
{
// Index and address of next frame.
tao_shared_camera* cam = fg->camera;
int index = fg->serial%fg->nbufs;
tao_shared_array* arr = fg->list[index];
if (arr != NULL) {
bool drop = true;
if (is_suitable(arr, cam)) {
// Array is suitable to store next frame data, try to lock it for
// writing.
tao_status code = tao_shared_array_try_wrlock(arr);
if (code == TAO_OK) {
// Shared array is now locked for writing.
drop = false;
} else if (code != TAO_TIMEOUT) {
// Some error occured.
return NULL;
}
}
if (drop == true) {
// Drop the shared array.
fg->list[index] = NULL;
if (tao_shared_array_detach(arr) != TAO_OK) {
return NULL;
}
arr = NULL;
}
}
// If no suitable spare array was available, allocate a new shared array to
// store the next frame data and lock it for writing.
if (arr == NULL) {
arr = allocate_frame(cam, fg->flags);
if (arr == NULL) {
return NULL;
}
fg->list[index] = arr;
if (tao_shared_array_wrlock(arr) != TAO_OK) {
return NULL;
}
}
// Update information and return shared array.
arr->serial = 0; // to indicate that this buffer is not valid
for (int i = 0; i < TAO_SHARED_ARRAY_TIMESTAMPS; ++i) {
arr->ts[i] = TAO_UNKNOWN_TIME;
}
return arr;
}
tao_status tao_start_framegrabber_acquisition(
tao_framegrabber* fg)
{
// Minimal checking. NOTE: It is assumed that the caller has locked the
// shared camera for read-write access.
if (fg == NULL || fg->camera == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return TAO_ERROR;
}
if (fg->locked == NULL) {
fg->locked = fetch_next_frame(fg);
if (fg->locked == NULL) {
return TAO_ERROR;
}
fg->camera->nextframe = fg->locked->base.base.shmid;
}
return TAO_OK;
}
tao_status tao_stop_framegrabber_acquisition(
tao_framegrabber* fg)
{
// Minimal checking. NOTE: It is assumed that the caller has locked the
// shared camera for read-write access.
if (fg == NULL || fg->camera == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return TAO_ERROR;
}
fg->camera->nextframe = TAO_BAD_SHMID;
if (fg->locked != NULL) {
tao_shared_array* arr = fg->locked;
fg->locked = NULL;
if (tao_shared_array_unlock(arr) != TAO_OK) {
return TAO_ERROR;
}
}
return TAO_OK;
}
tao_status tao_post_framegrabber_buffer(
tao_framegrabber* fg)
{
// Minimal checking. NOTE: It is assumed that the caller has locked the
// shared camera for read-write access.
if (fg == NULL || fg->camera == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return TAO_ERROR;
}
// Post current acquisition frame buffer if any.
if (fg->locked != NULL) {
tao_shared_array* arr = fg->locked;
fg->locked = NULL;
fg->serial += 1;
arr->serial = fg->serial;
if (TAO_SHARED_ARRAY_TIMESTAMPS >= 4) {
tao_time t;
if (tao_get_monotonic_time(&t) == TAO_OK) {
arr->ts[3] = t;
} else {
tao_report_error();
}
}
if (tao_shared_array_unlock(arr) != TAO_OK) {
return TAO_ERROR;
}
fg->camera->serial = fg->serial;
fg->camera->lastframe = arr->base.base.shmid;
}
// Fetch next acquisition frame buffer.
fg->locked = fetch_next_frame(fg);
if (fg->locked == NULL) {
return TAO_ERROR;
}
fg->camera->nextframe = fg->locked->base.base.shmid;
return TAO_OK;
}
tao_shared_array* tao_attach_last_image(
tao_shared_camera* cam)
{
if (cam == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return NULL;
}
tao_shmid shmid = cam->lastframe;
return (shmid == TAO_BAD_SHMID ? NULL :
tao_shared_array_attach(shmid));
}
tao_shared_array* tao_attach_next_image(
tao_shared_camera* cam)
{
if (cam == NULL) {
tao_store_error(__func__, TAO_BAD_ADDRESS);
return NULL;
}
tao_shmid shmid = cam->nextframe;
return (shmid == TAO_BAD_SHMID ? NULL :
tao_shared_array_attach(shmid));
}
#define GETTER(type, path, member, def) \
type tao_shared_camera_get_##member( \
const tao_shared_camera* cam) \
{ \
return TAO_LIKELY(cam != NULL) ? cam->path.member : (def); \
}
GETTER(long, info, sensorwidth, 0)
GETTER(long, info, sensorheight, 0)
GETTER(long, info.config.roi, xbin, 0)
GETTER(long, info.config.roi, ybin, 0)
GETTER(long, info.config.roi, xoff, 0)
GETTER(long, info.config.roi, yoff, 0)
GETTER(long, info.config.roi, width, 0)
GETTER(long, info.config.roi, height, 0)
GETTER(double, info.config, framerate, 0.0)
GETTER(double, info.config, exposuretime, 0.0)
GETTER(tao_eltype, info.config, pixeltype, TAO_UINT8)
GETTER(tao_encoding, info.config, sensorencoding, TAO_ENCODING_UNKNOWN)
GETTER(tao_encoding, info.config, bufferencoding, TAO_ENCODING_UNKNOWN)
GETTER(tao_state, info, state, TAO_STATE_KILLED)
#undef GETTER
const char* tao_shared_camera_get_owner(
const tao_shared_camera* cam)
{
return (cam != NULL ? cam->owner : "");
}
long tao_shared_camera_get_nbufs(
const tao_shared_camera* cam)
{
return (cam != NULL ? cam->nbufs : 0);
}
tao_serial tao_shared_camera_get_serial(
const tao_shared_camera* cam)
{
return (cam != NULL ? cam->serial : 0);
}
tao_shmid tao_get_last_image_shmid(
const tao_shared_camera* cam)
{
return (cam != NULL ? cam->lastframe : TAO_BAD_SHMID);
}
tao_shmid tao_get_next_image_shmid(
const tao_shared_camera* cam)
{
return (cam != NULL ? cam->nextframe : TAO_BAD_SHMID);
}
// Generic shared object methods.
#define TYPE shared_camera
#define MAGIC TAO_SHARED_CAMERA
#define IS_RWLOCKED_OBJECT 1
#include "./shared-methods.c"
// shared-cameras.c -
//
// Management of shared cameras and virtual frame-grabbers.
//
//-----------------------------------------------------------------------------
//
// This file if part of TAO real-time software licensed under the MIT license
// (https://git-cral.univ-lyon1.fr/tao/tao-rt).
//
// Copyright (C) 2019-2022, Éric Thiébaut.
#include <string.h>
#include "tao-basics.h"
#include "tao-config.h"
#include "tao-errors.h"
#include "tao-generic.h"
#include "tao-macros.h"
#include "tao-shared-cameras-private.h"
#include "tao-shared-arrays-private.h"
#define FRAMEGRABBER_TRY_LOCK 0
tao_status tao_destroy_framegrabber(
tao_framegrabber* fg)
{
tao_status status = TAO_OK;
if (fg != NULL) {
if (fg->camera != NULL) {
tao_shared_camera* cam = fg->camera;
fg->camera = NULL;
if (tao_shared_camera_detach(cam) != TAO_OK) {
status = TAO_ERROR;
}
}
if (fg->locked != NULL) {
tao_shared_array* arr = fg->locked;
fg->locked = NULL;
if (tao_shared_array_unlock(arr) != TAO_OK) {
status = TAO_ERROR;
}
}
if (fg->list != NULL) {
tao_shared_array** list = fg->list;
for (int i = 0; i < fg->nbufs; ++i) {
tao_shared_array* arr = list[i];
list[i] = NULL;
if (arr != NULL &&
tao_shared_array_detach(arr) != TAO_OK) {
status = TAO_ERROR;
}
}
fg->list = NULL;
free(list);
}
free(fg);
}
return status;
}
tao_framegrabber* tao_create_framegrabber(
const char* owner,
int nbufs,
unsigned flags)
{
long len = TAO_STRLEN(owner);
if (len < 1) {
tao_store_error(__func__, TAO_BAD_NAME);
return NULL;
}
if (nbufs < 2) {
tao_store_error(__func__, TAO_BAD_ARGUMENT);
return NULL;
}
tao_framegrabber* fg = TAO_NEW(1, tao_framegrabber);
if (fg == NULL) {
return NULL;
}
fg->flags = flags;
fg->list = TAO_NEW(nbufs, tao_shared_array*);
if (fg->list == NULL) {
tao_destroy_framegrabber(fg);
return NULL;
}
tao_forced_store(&fg->nbufs, nbufs);
fg->serial = 0;
tao_shared_camera* cam = (tao_shared_camera*)tao_rwlocked_object_create(
TAO_SHARED_CAMERA, sizeof(tao_shared_camera), flags);
if (cam == NULL) {
tao_destroy_framegrabber(fg);
return NULL;
}
for (long i = 0; i < len; ++i) {
((char*)cam->owner)[i] = owner[i];
}
((char*)cam->owner)[len] = '\0';
fg->camera = cam;
tao_camera_info_initialize(&cam->info);
tao_forced_store(&cam->nbufs, nbufs);
cam->serial = fg->serial;
cam->lastframe = TAO_BAD_SHMID;
cam->nextframe = TAO_BAD_SHMID;
return fg;
}
tao_shared_camera* tao_get_framegrabber_shared_camera(
tao_framegrabber* fg)
{
return (fg != NULL ? fg->camera : NULL);
}
tao_shared_array* tao_get_framegrabber_buffer(
tao_framegrabber* fg)
{
return (fg != NULL ? fg->locked : NULL);
}
static tao_shared_array* allocate_frame(
tao_shared_camera* cam,
unsigned flags)
{
tao_shared_array* arr;
if (cam->info.config.weighted == false) {
arr = tao_shared_array_create_2d(cam->info.config.pixeltype,
cam->info.config.roi.width,
cam->info.config.roi.height,
flags);
} else {
arr = tao_shared_array_create_3d(cam->info.config.pixeltype,
cam->info.config.roi.width,
cam->info.config.roi.height,
2, flags);
}
return arr;
}
// Yield whether shared array `arr` is suitable to store the frame data for
// shared camera `cam`. The shared camera should be locked by the caller but
// the shared array may not be locked as all checked parameters are, in
// principle, read-only by every one. This may be used to avoid the overheads
// of locking the array.
static inline int is_suitable(
const tao_shared_array* arr,
const tao_shared_camera* cam)
{
return (TAO_SHARED_ARRAY_SHMID(arr) != cam->lastframe &&
arr->eltype == cam->info.config.pixeltype &&
arr->dims[0] == cam->info.config.roi.width &&