#include #include #include #include #include "ufo-roof.h" #include "ufo-roof-error.h" #include "ufo-roof-config.h" #define roof_config_node_get_with_default(var, parent, type, name, default) do { \ JsonNode *node = json_object_get_member(parent, name); \ if (node) var = json_node_get_##type(node); \ else var = default; \ } while(0) #define roof_config_node_get_string_with_default(var, parent, name, default) do { \ const gchar *str; \ JsonNode *node = json_object_get_member(parent, name); \ if (node) str = json_node_get_string(node); \ else str = default; \ if (var != str) { \ if (var) g_free(var); \ var = g_strdup(str); \ } \ } while(0) #define roof_config_node_get(var, parent, type, name) \ roof_config_node_get_with_default(var, parent, type, name, var) #define roof_config_node_get_string(var, parent, name) \ roof_config_node_get_string_with_default(var, parent, name, var) typedef struct { RoofConfig cfg; JsonParser *parser; } RoofConfigPrivate; void roof_config_free(RoofConfig *cfg) { if (cfg) { RoofConfigPrivate *priv = (RoofConfigPrivate*)cfg; if (priv->parser) g_object_unref (priv->parser); free(cfg); } } RoofConfig *roof_config_new(const char *config, RoofConfigFlags flags, GError **error) { RoofConfigPrivate *priv; RoofConfig *cfg; // 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; JsonObject *data = NULL; GError *gerr = NULL; priv = (RoofConfigPrivate*)malloc(sizeof(RoofConfigPrivate)); if (!priv) roof_new_error(error, "Can't allocate RoofConfig"); memset(priv, 0, sizeof(RoofConfigPrivate)); // Set defaults cfg = &priv->cfg; 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 = 100000000; // FIXME: remove 0 cfg->header_size = sizeof(RoofPacketHeader); cfg->payload_size = 0; cfg->max_packet_size = 0; cfg->max_packets = 100; cfg->dataset_size = 0; cfg->buffer_size = 2; cfg->latency_buffers = 0; cfg->drop_buffers = 0; cfg->sockets_per_thread = 4; // Read configuration priv->parser = json_parser_new_immutable (); json_parser_load_from_file (priv->parser, config, &gerr); if (gerr != NULL) { g_propagate_prefixed_error(error, gerr, "Error parsing JSON file (%s) with ROOF configuration: ", config); roof_config_free(cfg); return NULL; } root = json_node_get_object (json_parser_get_root (priv->parser)); 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(performance, root, object, "performance"); roof_config_node_get(data, root, object, "data"); if (flags&ROOF_CONFIG_SIMULATION) roof_config_node_get(simulation, root, object, "simulation"); } if (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)) { 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))) { 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)) { 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) { roof_config_node_get(cfg->port, network, int, "port"); roof_config_node_get(cfg->n_streams, network, int, "streams"); 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->max_packet_size, network, int, "max_packet_size"); roof_config_node_get(cfg->dataset_size, network, int, "dataset_size"); if (!cfg->payload_size) { roof_config_free(cfg); roof_new_error(error, "Packet payload and header size must be set"); } if ((cfg->header_size < sizeof(RoofPacketHeader))&&(!strncmp(cfg->protocol, "udp", 3))) { roof_config_free(cfg); roof_new_error(error, "The header with packet id (%lu bytes) is expected for un-ordered protocols", sizeof(RoofPacketHeader)); } if (!cfg->dataset_size) cfg->dataset_size = cfg->payload_size; } if (simulation) { roof_config_node_get(cfg->header_size, simulation, int, "header_size"); if (!cfg->payload_size) cfg->payload_size = cfg->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->latency_buffers, performance, int, "latency_buffers"); roof_config_node_get(cfg->sockets_per_thread, performance, int, "sockets_per_thread"); } // 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)) { 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); } // 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)))) { 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); } if (!cfg->max_packet_size) cfg->max_packet_size = cfg->header_size + cfg->payload_size; if (hardware) { if (cfg->n_modules != cfg->n_streams) { 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)) { 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->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; } else if (cfg->drop_buffers >= cfg->buffer_size) { cfg->drop_buffers = cfg->buffer_size / 2; } return cfg; }