summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2020-01-26 08:14:32 +0100
committerSuren A. Chilingaryan <csa@suren.me>2020-01-26 08:14:32 +0100
commitea424f096c05a9587ffaa0bc6e5392790a046bd7 (patch)
tree01d0f9c596ebea229e6a8e2774a7a69a502a3488 /src
parent02b452a86d11655002fdfbb1566ef494e2c954d2 (diff)
downloadufo-roof-ea424f096c05a9587ffaa0bc6e5392790a046bd7.tar.gz
ufo-roof-ea424f096c05a9587ffaa0bc6e5392790a046bd7.tar.bz2
ufo-roof-ea424f096c05a9587ffaa0bc6e5392790a046bd7.tar.xz
ufo-roof-ea424f096c05a9587ffaa0bc6e5392790a046bd7.zip
Build ROOF sinograms
Diffstat (limited to 'src')
-rw-r--r--src/ufo-roof-buffer.c34
-rw-r--r--src/ufo-roof-buffer.h7
-rw-r--r--src/ufo-roof-build-task.c86
-rw-r--r--src/ufo-roof-config.c143
-rw-r--r--src/ufo-roof-config.h43
-rw-r--r--src/ufo-roof.h2
6 files changed, 243 insertions, 72 deletions
diff --git a/src/ufo-roof-buffer.c b/src/ufo-roof-buffer.c
index 179d153..bac940c 100644
--- a/src/ufo-roof-buffer.c
+++ b/src/ufo-roof-buffer.c
@@ -9,15 +9,24 @@
// This is currently not thread safe. With dual-filter architecture this will be called sequentially.
-UfoRoofBuffer *ufo_roof_buffer_new(UfoRoofConfig *cfg, guint max_datasets, GError **error) {
+UfoRoofBuffer *ufo_roof_buffer_new(UfoRoofConfig *cfg, guint n_dims, guint max_datasets, GError **error) {
+ if ((n_dims < 1)||(n_dims > 2))
+ roof_new_error(error, "Unsupported number of dimmensions %u (only plain and 2D ROOF structure is currently supported)", n_dims);
+
UfoRoofBuffer *buffer = (UfoRoofBuffer*)calloc(1, sizeof(UfoRoofBuffer));
if (!buffer) roof_new_error(error, "Can't allocate UfoRoofBuffer");
buffer->max_datasets = max_datasets;
buffer->ring_size = cfg->buffer_size;
buffer->drop_buffers = cfg->drop_buffers;
- buffer->fragment_size = cfg->payload_size;
+ buffer->n_dims = n_dims;
buffer->dataset_size = cfg->dataset_size;
+ buffer->dataset_dims[0] = cfg->fan_bins * cfg->bit_depth / 8;
+ buffer->dataset_dims[1] = cfg->fan_projections;
+ buffer->fragment_size = cfg->payload_size;
+ buffer->fragment_dims[0] = cfg->channels_per_module * cfg->bit_depth / 8;
+ buffer->fragment_dims[1] = buffer->fragment_size / buffer->fragment_dims[0];
+
buffer->fragments_per_dataset = buffer->dataset_size / buffer->fragment_size;
buffer->fragments_per_stream = buffer->fragments_per_dataset / cfg->n_streams;
// printf("Configuration: dataset: %u - %u fragments (%u streams x %u) x %u bytes\n", buffer->dataset_size, buffer->fragments_per_dataset, cfg->n_streams, buffer->fragments_per_stream, buffer->fragment_size);
@@ -96,15 +105,25 @@ gboolean ufo_roof_buffer_set_fragment(UfoRoofBuffer *buffer, guint stream_id, gu
// The updates may happen after writting/reading is finished.
}
- // FIXME: This is builds events as it read from file in roof v.1 code. We can assemble fan projections directly here.
- uint8_t *dataset_buffer = buffer->ring_buffer + buffer_id * buffer->dataset_size;
- uint8_t *fragment_buffer = dataset_buffer + (stream_id * buffer->fragments_per_stream + fragment_id) * buffer->fragment_size;
-
/* printf("buffer: %u (%u), packet: %u (%ux%u %u), packet_size: %u [%x]\n",
buffer_id, dataset_id, stream_id * buffer->fragments_per_stream + fragment_id, stream_id, buffer->fragments_per_stream, fragment_id, buffer->fragment_size,
((uint32_t*)fragment)[0]
);*/
- memcpy(fragment_buffer, fragment, buffer->fragment_size);
+
+ uint8_t *dataset_buffer = buffer->ring_buffer + buffer_id * buffer->dataset_size;
+ if (buffer->n_dims == 2) {
+ uint8_t *fragment_buffer = dataset_buffer +
+ stream_id * buffer->fragment_dims[0] + // x-coordinate
+ (fragment_id * buffer->fragment_dims[1]) * buffer->dataset_dims[0]; // y-coordinate
+
+ for (int i = 0; i < buffer->fragment_dims[1]; ++i) {
+ memcpy(fragment_buffer + i * buffer->dataset_dims[0], fragment + i * buffer->fragment_dims[0], buffer->fragment_dims[0]);
+ }
+ } else {
+ // 1D stracture, simply putting fragment at the appropriate position in the stream
+ uint8_t *fragment_buffer = dataset_buffer + (stream_id * buffer->fragments_per_stream + fragment_id) * buffer->fragment_size;
+ memcpy(fragment_buffer, fragment, buffer->fragment_size);
+ }
// FIXME: Sanity checks: verify is not a dublicate fragment?
atomic_fetch_add(&buffer->n_fragments[buffer_id], 1);
@@ -128,6 +147,7 @@ gboolean ufo_roof_buffer_get_dataset(UfoRoofBuffer *buffer, gpointer output_buff
if (buffer->n_fragments[buffer_id] < buffer->fragments_per_dataset) return FALSE;
memcpy(output_buffer, dataset_buffer, buffer->dataset_size);
+
buffer->n_fragments[buffer_id] = 0;
buffer->current_id += 1;
diff --git a/src/ufo-roof-buffer.h b/src/ufo-roof-buffer.h
index c4c8474..7ebaec9 100644
--- a/src/ufo-roof-buffer.h
+++ b/src/ufo-roof-buffer.h
@@ -15,16 +15,19 @@ struct _UfoRoofBuffer {
guint max_datasets; // Only the specified number of datasets will be buffered, the rest will be silently dropped
+ guint n_dims; // Indicates if we just assemble one fragment after another or there is 2D/3D data structure (ROOF)
guint dataset_size; // Size (in bytes) of a full dataset
+ guint dataset_dims[2]; // x (in bytes), y (in rows)
guint fragment_size; // Size (in bytes) of a single fragment (we expect fixed-size fragments at the moment)
-
+ guint fragment_dims[2]; // x (in bytes), y (in rows)
+
guint fragments_per_dataset; // Number of packets in dataset (used to compute when dataset is ready)
guint fragments_per_stream; // Number of packets in each of data streams (used to compute when dataset is ready)
};
typedef struct _UfoRoofBuffer UfoRoofBuffer;
-UfoRoofBuffer *ufo_roof_buffer_new(UfoRoofConfig *cfg, guint max_datasets, GError **error);
+UfoRoofBuffer *ufo_roof_buffer_new(UfoRoofConfig *cfg, guint n_dims, guint max_datasets, GError **error);
void ufo_roof_buffer_free(UfoRoofBuffer *buf);
gboolean ufo_roof_buffer_set_fragment(UfoRoofBuffer *buffer, guint stream_id, guint fragment_id, gconstpointer fragment, GError **error);
diff --git a/src/ufo-roof-build-task.c b/src/ufo-roof-build-task.c
index e5e5518..8af44db 100644
--- a/src/ufo-roof-build-task.c
+++ b/src/ufo-roof-build-task.c
@@ -29,12 +29,19 @@
#include "ufo-roof-buffer.h"
#include "ufo-roof-build-task.h"
+typedef enum {
+ BUILD_AUTO = 0,
+ BUILD_RAW,
+ BUILD_SINO,
+ BUILD_UFO
+} BuildType;
struct _UfoRoofBuildTaskPrivate {
gchar *config; // ROOF configuration file name
UfoRoofConfig *cfg; // Parsed ROOF parameters
UfoRoofBuffer *buf; // Ring buffer for incomming UDP packet
+ BuildType build; // What dataset do we build: ROOF sinogram or raw network data
guint number; // Number of datasets to read
gboolean stop; // Stop flag
@@ -51,10 +58,21 @@ G_DEFINE_TYPE_WITH_CODE (UfoRoofBuildTask, ufo_roof_build_task, UFO_TYPE_TASK_NO
#define UFO_ROOF_BUILD_TASK_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_ROOF_BUILD_TASK, UfoRoofBuildTaskPrivate))
+
+
+static GEnumValue build_values[] = {
+ { BUILD_AUTO, "BUILD_AUTO", "auto" },
+ { BUILD_RAW, "BUILD_RAW", "raw" },
+ { BUILD_SINO, "BUILD_SINO", "sino" },
+ { BUILD_UFO, "BUILD_UFO", "ufo" },
+ { 0, NULL, NULL}
+};
+
enum {
PROP_0,
PROP_STOP,
PROP_NUMBER,
+ PROP_BUILD,
PROP_CONFIG,
N_PROPERTIES
};
@@ -83,8 +101,13 @@ ufo_roof_build_task_setup (UfoTask *task,
if (!priv->cfg)
roof_propagate_error(error, gerr, "roof-build-setup: ");
+ if (priv->build == BUILD_AUTO) {
+ if (priv->cfg->roof_mode) priv->build = BUILD_SINO;
+ else priv->build = BUILD_RAW;
+ g_object_notify_by_pspec (G_OBJECT(task), properties[PROP_BUILD]);
+ }
- priv->buf = ufo_roof_buffer_new(priv->cfg, priv->number, &gerr);
+ priv->buf = ufo_roof_buffer_new(priv->cfg, (priv->build == BUILD_RAW)?1:2, priv->number, &gerr);
if (!priv->buf)
roof_propagate_error(error, gerr, "roof-build-setup: ");
@@ -103,7 +126,7 @@ ufo_roof_build_task_finalize (GObject *object)
if (priv->cfg) {
ufo_roof_config_free(priv->cfg);
- priv->cfg = NULL;
+ priv->cfg = NULL;
}
if (priv->config) {
@@ -125,12 +148,21 @@ ufo_roof_build_task_get_requisition (UfoTask *task,
{
UfoRoofBuildTaskPrivate *priv = UFO_ROOF_BUILD_TASK_GET_PRIVATE (task);
- guint bytes = priv->cfg->dataset_size;
-
- // FIXME: Can this be made more elegant?
- requisition->n_dims = 1;
- requisition->dims[0] = bytes / sizeof(float) + ((bytes%sizeof(float))?1:0);
-
+ // FIXME: Can we handle data types more elegant?
+ if (priv->build == BUILD_RAW) {
+ guint bytes = priv->cfg->dataset_size;
+ requisition->n_dims = 1;
+ requisition->dims[0] = bytes / sizeof(float) + ((bytes%sizeof(float))?1:0);
+ } else if (priv->build == BUILD_SINO) {
+ guint bytes = priv->cfg->fan_bins * priv->cfg->bit_depth / 8;
+ requisition->n_dims = 2;
+ requisition->dims[0] = bytes / sizeof(float) + ((bytes%sizeof(float))?1:0);
+ requisition->dims[1] = priv->cfg->fan_projections;
+ } else if (priv->build == BUILD_UFO) {
+ requisition->n_dims = 2;
+ requisition->dims[0] = priv->cfg->fan_bins;
+ requisition->dims[1] = priv->cfg->fan_projections;
+ }
}
static guint
@@ -222,9 +254,9 @@ ufo_roof_build_task_generate (UfoTask *task,
{
gboolean ready = FALSE;
GError *gerr = NULL;
-
+
UfoRoofBuildTaskPrivate *priv = UFO_ROOF_BUILD_TASK_GET_PRIVATE (task);
-// UfoRoofConfig *cfg = priv->cfg;
+ UfoRoofConfig *cfg = priv->cfg;
UfoRoofBuffer *buf = priv->buf;
void *output_buffer = ufo_buffer_get_host_array(output, NULL);
@@ -235,6 +267,20 @@ ufo_roof_build_task_generate (UfoTask *task,
ready = ufo_roof_buffer_get_dataset(buf, output_buffer, &gerr);
if (gerr) roof_print_error(gerr);
+ if (priv->build == BUILD_UFO) {
+ switch (cfg->bit_depth) {
+ case 8:
+ ufo_buffer_convert(output, UFO_BUFFER_DEPTH_8U);
+ break;
+ case 16:
+ ufo_buffer_convert(output, UFO_BUFFER_DEPTH_16U);
+ break;
+ case 32:
+ ufo_buffer_convert(output, UFO_BUFFER_DEPTH_32U);
+ break;
+ }
+ }
+
// FIXME: Or shall we start from counting from the ID of the first registerd dataset
if ((priv->number)&&(buf->current_id >= priv->number)) {
// printf("%u datasets processed, stopping\n", buf->current_id);
@@ -242,8 +288,7 @@ ufo_roof_build_task_generate (UfoTask *task,
g_object_notify_by_pspec (G_OBJECT(task), properties[PROP_STOP]);
}
-
- if ((priv->number < 100)||((buf->current_id - priv->announced) > 1000)) {
+ if (((priv->number > 0)&&(priv->number <= 100))||((buf->current_id - priv->announced) > 1000)) {
printf("Generating dataset %i (%s), next: %u out of %u)\n", buf->current_id, ready?"yes":" no", buf->n_fragments[buf->current_id%buf->ring_size], buf->fragments_per_dataset);
priv->announced = buf->current_id;
}
@@ -270,6 +315,13 @@ ufo_roof_build_task_set_property (GObject *object,
case PROP_NUMBER:
priv->number = g_value_get_uint (value);
break;
+ case PROP_BUILD:
+ priv->build = g_value_get_enum (value);
+ if ((priv->build == BUILD_AUTO)&&(priv->cfg)) {
+ if (priv->cfg->roof_mode) priv->build = BUILD_SINO;
+ else priv->build = BUILD_RAW;
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -294,6 +346,9 @@ ufo_roof_build_task_get_property (GObject *object,
case PROP_NUMBER:
g_value_set_uint (value, priv->number);
break;
+ case PROP_BUILD:
+ g_value_set_enum (value, priv->build);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
@@ -342,6 +397,13 @@ ufo_roof_build_task_class_init (UfoRoofBuildTaskClass *klass)
0, G_MAXUINT, 0,
G_PARAM_READWRITE);
+ properties[PROP_BUILD] =
+ g_param_spec_enum ("build",
+ "Build type (\"raw\", \"sino\", \"ufo\")",
+ "Build type (\"raw\" - raw data, \"sino\" - arrange in sinogram, \"ufo\" - arrange in sinogram and convert UFO floating-point format)",
+ g_enum_register_static ("build", build_values),
+ 0, G_PARAM_READWRITE);
+
for (guint i = PROP_0 + 1; i < N_PROPERTIES; i++)
g_object_class_install_property (oclass, i, properties[i]);
diff --git a/src/ufo-roof-config.c b/src/ufo-roof-config.c
index 812d4a2..4788a2a 100644
--- a/src/ufo-roof-config.c
+++ b/src/ufo-roof-config.c
@@ -5,6 +5,7 @@
#include <ufo/ufo.h>
+#include "ufo-roof.h"
#include "ufo-roof-error.h"
#include "ufo-roof-config.h"
@@ -59,10 +60,13 @@ UfoRoofConfig *ufo_roof_config_new(const char *config, GError **error) {
// JsonNode *node;
JsonObject *root = NULL;
JsonObject *hardware = NULL;
+ JsonObject *geometry = NULL;
+ JsonObject *optics = NULL;
JsonObject *network = NULL;
JsonObject *performance = NULL;
JsonObject *simulation = NULL;
-
+ JsonObject *reconstruction = NULL;
+
GError *gerr = NULL;
priv = (UfoRoofConfigPrivate*)malloc(sizeof(UfoRoofConfigPrivate));
@@ -73,11 +77,20 @@ UfoRoofConfig *ufo_roof_config_new(const char *config, GError **error) {
// Set defaults
cfg = &priv->cfg;
- cfg->port = 4000;
+ cfg->roof_mode = FALSE;
+ cfg->n_planes = 2;
+ cfg->n_modules = 16;
+ cfg->channels_per_module = 16;
+ cfg->bit_depth = 16;
+ cfg->samples_per_rotation = 1000;
+ cfg->sample_rate = 0;
+ cfg->imaging_rate = 0;
+
+ cfg->port = 52067;
cfg->n_streams = 1;
cfg->protocol = "udp";
cfg->network_timeout = 10000000;
- cfg->header_size = 0;
+ cfg->header_size = sizeof(UfoRoofPacketHeader);
cfg->payload_size = 0;
cfg->max_packet_size = 0;
cfg->max_packets = 100;
@@ -86,11 +99,12 @@ UfoRoofConfig *ufo_roof_config_new(const char *config, GError **error) {
cfg->drop_buffers = 0;
cfg->path = NULL;
+
// Read configuration
priv->parser = json_parser_new_immutable ();
json_parser_load_from_file (priv->parser, config, &gerr);
- if (gerr != NULL) {
+ if (gerr != NULL) {
g_propagate_prefixed_error(error, gerr, "Error parsing JSON file (%s) with ROOF configuration: ", config);
ufo_roof_config_free(cfg);
return NULL;
@@ -100,75 +114,124 @@ UfoRoofConfig *ufo_roof_config_new(const char *config, GError **error) {
if (root) {
roof_config_node_get(hardware, root, object, "hardware");
+ roof_config_node_get(geometry, root, object, "geometry");
+ roof_config_node_get(optics, root, object, "optics");
roof_config_node_get(network, root, object, "network");
+ roof_config_node_get(reconstruction, root, object, "reconstruction");
roof_config_node_get(simulation, root, object, "simulation");
roof_config_node_get(performance, root, object, "performance");
}
if (hardware) {
- // FIXME: Compute dataset size based on roof hardware
+ roof_config_node_get(cfg->n_planes, hardware, int, "planes");
+ roof_config_node_get(cfg->n_modules, hardware, int, "modules");
+ roof_config_node_get(cfg->channels_per_module, hardware, int, "channels_per_module");
+ roof_config_node_get(cfg->bit_depth, hardware, int, "bit_depth");
+
+ roof_config_node_get(cfg->samples_per_rotation, hardware, int, "samples_per_rotation");
+ roof_config_node_get(cfg->sample_rate, hardware, int, "sample_rate");
+ roof_config_node_get(cfg->imaging_rate, hardware, int, "imaging_rate");
+
+ if ((cfg->sample_rate)||(cfg->imaging_rate)) {
+ if ((!cfg->sample_rate)||(!cfg->imaging_rate)||(cfg->sample_rate%cfg->imaging_rate)) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "Invalid sample (%u) and imaging (%u) rates are specified", cfg->sample_rate, cfg->imaging_rate);
+ }
+
+ if ((json_object_get_member(hardware, "samples_per_rotation"))&&(cfg->samples_per_rotation != (cfg->sample_rate / cfg->imaging_rate))) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "The specified samples-per-rotation (%u) doesn't match sample/imaging rates (%u / %u)", cfg->samples_per_rotation, cfg->sample_rate, cfg->imaging_rate);
+ }
+
+ cfg->samples_per_rotation = cfg->sample_rate / cfg->imaging_rate;
+ }
+
+ if ((cfg->bit_depth%8)||(cfg->bit_depth > 32)) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "Invalid bit-depth (%u) is configured, only 8, 16, 24, 32 is currently supported", cfg->bit_depth);
+ }
+
+ cfg->fan_projections = cfg->samples_per_rotation;
+ cfg->fan_bins = cfg->n_modules * cfg->channels_per_module;
+
+ cfg->dataset_size = cfg->fan_projections * cfg->fan_bins * (cfg->bit_depth / 8);
+ cfg->n_streams = cfg->n_modules;
+ cfg->roof_mode = TRUE;
}
if (network) {
-// int max_packet_size = 0;
-
roof_config_node_get(cfg->port, network, int, "port");
roof_config_node_get(cfg->n_streams, network, int, "streams");
- roof_config_node_get(cfg->max_packet_size, network, int, "max_packet_size");
- // FIXME: compute payload_size based on sample_size
roof_config_node_get(cfg->payload_size, network, int, "payload_size");
roof_config_node_get(cfg->header_size, network, int, "header_size");
- roof_config_node_get(cfg->dataset_size, network, int, "dataset_size");
- }
-
- if (performance) {
- roof_config_node_get(cfg->max_packets, performance, int, "packets_at_once");
- roof_config_node_get(cfg->buffer_size, performance, int, "buffer_size");
- roof_config_node_get(cfg->drop_buffers, performance, int, "drop_buffers");
+ roof_config_node_get(cfg->max_packet_size, network, int, "max_packet_size");
+ roof_config_node_get(cfg->dataset_size, network, int, "dataset_size");
+
+ if (!cfg->payload_size) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "Packet payload and header size must be set");
+ }
+
+ if ((cfg->header_size < sizeof(UfoRoofPacketHeader))&&(!strncmp(cfg->protocol, "udp", 3))) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "The header with packet id (%lu bytes) is expected for un-ordered protocols", sizeof(UfoRoofPacketHeader));
+ }
+
+ if (!cfg->dataset_size)
+ cfg->dataset_size = cfg->payload_size;
}
if (simulation) {
roof_config_node_get_string(cfg->path, simulation, "path");
roof_config_node_get(cfg->first_file_number, simulation, int, "first_file_number");
+ roof_config_node_get(cfg->header_size, simulation, int, "header_size");
+
+ if (!cfg->payload_size)
+ cfg->payload_size = cfg->dataset_size;
}
- // Check configuration consistency
- if (!cfg->payload_size) {
- ufo_roof_config_free(cfg);
- roof_new_error(error, "Packet size is not set");
- }
-
- if ((!cfg->header_size)&&(!cfg->path)) {
- if (!strncmp(cfg->protocol, "udp", 3)) {
- // Error if 0 implicitely set, use default value otherwise
- if ((network)&&(json_object_get_member(network, "header_size"))) {
- ufo_roof_config_free(cfg);
- roof_new_error(error, "The header with packet ids is required for un-ordered protocols");
- } else {
- cfg->header_size = sizeof(uint32_t);
- }
- }
+ if (performance) {
+ roof_config_node_get(cfg->max_packets, performance, int, "packets_at_once");
+ roof_config_node_get(cfg->buffer_size, performance, int, "buffer_size");
+ roof_config_node_get(cfg->drop_buffers, performance, int, "drop_buffers");
}
+
+ // Check configuration consistency
guint fragments_per_dataset = cfg->dataset_size / cfg->payload_size;
guint fragments_per_stream = fragments_per_dataset / cfg->n_streams;
+ // Dataset should be split in an integer number of network packets (we don't expect data from different datasets in one packet at the moment)
if ((cfg->dataset_size % cfg->payload_size)||(fragments_per_dataset%cfg->n_streams)) {
ufo_roof_config_free(cfg);
roof_new_error(error, "Inconsistent ROOF configuration: dataset_size=%u, packet_size=%u, data_streams=%u", cfg->dataset_size, cfg->payload_size, cfg->n_streams);
}
- if (cfg->buffer_size * fragments_per_stream < cfg->max_packets) {
- cfg->max_packets = cfg->buffer_size * fragments_per_stream / 2;
+ // Packet should contain an integer number of complete projections (their parts provided by a single module)
+ if ((cfg->roof_mode)&&(cfg->payload_size % (cfg->channels_per_module * (cfg->bit_depth / 8)))) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "Inconsistent ROOF configuration: packet_size=%u, projection_size=%u (%u channels x %u bits)", cfg->payload_size, cfg->channels_per_module * (cfg->bit_depth / 8), cfg->channels_per_module, cfg->bit_depth);
}
-
- // Finalize configuration
+
if (!cfg->max_packet_size)
- cfg->max_packet_size = cfg->header_size + cfg->payload_size;
+ cfg->max_packet_size = cfg->header_size + cfg->payload_size;
+
+ if (hardware) {
+ if (cfg->n_modules != cfg->n_streams) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "Currently, number of ROOF modules (%u) is exepcted to be equal to number of independent data streams (%u)", cfg->n_modules, cfg->n_streams);
+ }
+
+ if (cfg->dataset_size != (cfg->fan_projections * cfg->fan_bins * cfg->bit_depth / 8)) {
+ ufo_roof_config_free(cfg);
+ roof_new_error(error, "Specified dataset size (%u) does not match ROOF configuration (modules: %u, channels-per-module: %u, bit-depth: %u, samples-per-rotation: %u)", cfg->dataset_size, cfg->n_modules, cfg->channels_per_module, cfg->bit_depth, cfg->samples_per_rotation);
+ }
+ }
- if (!cfg->dataset_size)
- cfg->dataset_size = cfg->payload_size;
+ if ((cfg->buffer_size * fragments_per_stream) < cfg->max_packets) {
+ cfg->max_packets = cfg->buffer_size * fragments_per_stream / 2;
+ }
if (cfg->buffer_size < 4) {
cfg->drop_buffers = 0;
@@ -176,5 +239,7 @@ UfoRoofConfig *ufo_roof_config_new(const char *config, GError **error) {
cfg->drop_buffers = cfg->buffer_size / 2;
}
+ printf("dataset size: %i\n", cfg->dataset_size);
+
return cfg;
}
diff --git a/src/ufo-roof-config.h b/src/ufo-roof-config.h
index f90c5f3..b6ee748 100644
--- a/src/ufo-roof-config.h
+++ b/src/ufo-roof-config.h
@@ -4,30 +4,51 @@
#include <glib.h>
typedef struct {
+ // ROOF Hardware
+ gboolean roof_mode; // Indicates if ROOF is configured (1), otherwise only networking is implemented
+ guint n_planes; // Number of detector planes, ROOF module serves a ring segment from all planes in a round-robin fashion
+ guint n_modules; // Number of ROOF modules
+ guint channels_per_module; // Number of pixels in each module
+ guint samples_per_rotation; // Number of samples (projections) in a full fan sinogram; computed from sample_rate & image_rate if given
+ guint sample_rate; // Number of samples (projections) acquired per second, 0 - if unknown
+ guint imaging_rate; // Number of complete datasets (images) acquired per second, 0 - if unknown
+ guint bit_depth; // Number of bits per pixel (we currently support only multiples of 8)
+
+ // Geometry
+ guint fan_projections; // Number of fan projections = samples_per_rotation
+ guint fan_bins; // Number of fan detectors = n_modules * channels_per_module
+ guint parallel_projections;
+ guint parallel_bins;
+// guint detector_diameter;
+
+ // Optics
+
+
+ // Network Server / Reader
gchar *path; // Location of data files for simmulation purposes (i.e. reading a sequence of files instead listening on the corresponding ports)
guint first_file_number; // Indicates if the numbering of files starts at 0 or 1
gchar *protocol; // Protocols: tcp, udp, tcp6, udp6, ...
guint port; // First port
- guint n_streams; // Number of independent data streams (expected on sequential ports)
+ guint n_streams; // Number of independent data streams (expected on sequential ports), by default equal to number of ROOF modules
guint header_size; // Expected size of the packet header, for dgram protocols we need at least 32-bit sequence number. Defaults to uint32_t for udp* and 0 - otherwise
guint payload_size; // Expected size of TCP/UDP packet (without header)
- guint dataset_size; // Size of a single dataset (image, sinogram, etc.). This is real size in bytes, excluding all technical headers used in communication protocol.
+ guint dataset_size; // Size of a single dataset (image, sinogram, etc.). This is real size in bytes, excluding all technical headers used in communication protocol. Normally, it is computed based on ROOF hardware parameters.
+
+ // Performance parameters
+ guint max_packets; // limits maximum number of packets which are read at once
+ guint max_packet_size; // payload_size + header_size + ... (we don't care if tail is variable length provided that the complete packet does not exceed max_packet_size bytes)
+ guint buffer_size; // How many datasets we can buffer. There is no sense to have more than 2 for odered protocols (default), but having larger number could help for UDP if significant order disturbances are expected
+ guint drop_buffers; // If we are slow and lost some buffers, we may drop more than minimally necessary to catch up.
+ guint network_timeout; // Maximum time (us) to wait for data on the socket
+
-//?
/*
- guint pixels_per_module;
guint planes_per_module;
- guint samples_per_dataset;
*/
- guint max_packets; // limits maximum number of packets which are read at once
- guint max_packet_size; // payload_size + header_size + ...?
- guint buffer_size; // How many datasets we can buffer. There is no sense to have more than 2 for odered protocols (default), but having larger number could help for UDP if significant order disturbances are expected
- guint drop_buffers; // If we are slow and lost some buffers, we may drop more than minimally necessary to catch up.
- guint network_timeout; // Maximum time (us) to wait for data on the socket
-
+
} UfoRoofConfig;
diff --git a/src/ufo-roof.h b/src/ufo-roof.h
index d9d3a57..9303045 100644
--- a/src/ufo-roof.h
+++ b/src/ufo-roof.h
@@ -8,7 +8,7 @@
#define UFO_ROOF_PACKET_BLOCK_HEADER(buf, cfg) ((UfoRoofPacketBlockHeader*)(((uint8_t*)buf) + cfg->max_packets * cfg->max_packet_size))
typedef struct {
- uint32_t packet_id; // Sequential Packet ID (numbered from 0)
+ uint64_t packet_id; // Sequential Packet ID (numbered from 0)
} UfoRoofPacketHeader;
typedef struct {