mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
replaced libconfig by jansson for parsing the configuration (huge commit)
This commit is contained in:
parent
0f6aaafeb6
commit
434fe6dbd6
80 changed files with 1471 additions and 987 deletions
|
@ -33,5 +33,12 @@ json_t * config_to_json(config_setting_t *cfg);
|
|||
/* Convert a jansson object into a libconfig object. */
|
||||
int json_to_config(json_t *json, config_setting_t *parent);
|
||||
|
||||
/* Create a libconfig object from command line parameters. */
|
||||
int config_read_cli(config_t *cfg, int argc, char *argv[]);
|
||||
/* Create a JSON object from command line parameters. */
|
||||
json_t * json_load_cli(int argc, char *argv[]);
|
||||
|
||||
int json_object_extend_str(json_t *orig, const char *str);
|
||||
|
||||
void json_object_extend_key_value(json_t *obj, const char *key, const char *value);
|
||||
|
||||
/* Merge two JSON objects recursively. */
|
||||
int json_object_extend(json_t *orig, json_t *merge);
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "kernel/pci.h"
|
||||
#include "kernel/vfio.h"
|
||||
|
@ -70,9 +68,9 @@ struct fpga_card {
|
|||
int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *vc);
|
||||
|
||||
/** Parse configuration of FPGA card including IP cores from config. */
|
||||
int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg);
|
||||
int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name);
|
||||
|
||||
int fpga_card_parse_list(struct list *l, config_setting_t *cfg);
|
||||
int fpga_card_parse_list(struct list *l, json_t *cfg);
|
||||
|
||||
/** Check if the FPGA card configuration is plausible. */
|
||||
int fpga_card_check(struct fpga_card *c);
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
|
@ -60,7 +59,7 @@ struct fpga_ip_type {
|
|||
enum fpga_ip_types type;
|
||||
|
||||
int (*init)(struct fpga_ip *c);
|
||||
int (*parse)(struct fpga_ip *c);
|
||||
int (*parse)(struct fpga_ip *c, json_t *cfg);
|
||||
int (*check)(struct fpga_ip *c);
|
||||
int (*start)(struct fpga_ip *c);
|
||||
int (*stop)(struct fpga_ip *c);
|
||||
|
@ -93,7 +92,7 @@ struct fpga_ip {
|
|||
int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt);
|
||||
|
||||
/** Parse IP core configuration from configuration file */
|
||||
int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg);
|
||||
int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name);
|
||||
|
||||
/** Check configuration of IP core. */
|
||||
int fpga_ip_check(struct fpga_ip *c);
|
||||
|
|
|
@ -25,7 +25,7 @@ struct dft {
|
|||
int decimation;
|
||||
};
|
||||
|
||||
int dft_parse(struct fpga_ip *c);
|
||||
int dft_parse(struct fpga_ip *c, json_t *cfg);
|
||||
|
||||
int dft_start(struct fpga_ip *c);
|
||||
|
||||
|
|
|
@ -33,20 +33,20 @@ enum model_xsg_block_type {
|
|||
XSG_BLOCK_INFO = 0x2000
|
||||
};
|
||||
|
||||
enum model_param_type {
|
||||
MODEL_PARAM_TYPE_UFIX,
|
||||
MODEL_PARAM_TYPE_FIX,
|
||||
MODEL_PARAM_TYPE_FLOAT,
|
||||
MODEL_PARAM_TYPE_BOOLEAN
|
||||
enum model_parameter_type {
|
||||
MODEL_PARAMETER_TYPE_UFIX,
|
||||
MODEL_PARAMETER_TYPE_FIX,
|
||||
MODEL_PARAMETER_TYPE_FLOAT,
|
||||
MODEL_PARAMETER_TYPE_BOOLEAN
|
||||
};
|
||||
|
||||
enum model_param_direction {
|
||||
MODEL_PARAM_IN,
|
||||
MODEL_PARAM_OUT,
|
||||
MODEL_PARAM_INOUT
|
||||
enum model_parameter_direction {
|
||||
MODEL_PARAMETER_IN,
|
||||
MODEL_PARAMETER_OUT,
|
||||
MODEL_PARAMETER_INOUT
|
||||
};
|
||||
|
||||
union model_param_value {
|
||||
union model_parameter_value {
|
||||
uint32_t ufix;
|
||||
int32_t fix;
|
||||
float flt;
|
||||
|
@ -75,16 +75,16 @@ struct model_info {
|
|||
char *value;
|
||||
};
|
||||
|
||||
struct model_param {
|
||||
struct model_parameter {
|
||||
char *name; /**< Name of the parameter */
|
||||
|
||||
enum model_param_direction direction; /**< Read / Write / Read-write? */
|
||||
enum model_param_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */
|
||||
enum model_parameter_direction direction; /**< Read / Write / Read-write? */
|
||||
enum model_parameter_type type; /**< Data type. Integers are represented by MODEL_GW_TYPE_(U)FIX with model_gw::binpt == 0 */
|
||||
|
||||
int binpt; /**< Binary point for type == MODEL_GW_TYPE_(U)FIX */
|
||||
uintptr_t offset; /**< Register offset to model::baseaddress */
|
||||
|
||||
union model_param_value default_value;
|
||||
union model_parameter_value default_value;
|
||||
|
||||
struct fpga_ip *ip; /**< A pointer to the model structure to which this parameters belongs to. */
|
||||
};
|
||||
|
@ -93,7 +93,7 @@ struct model_param {
|
|||
int model_init(struct fpga_ip *c);
|
||||
|
||||
/** Parse model */
|
||||
int model_parse(struct fpga_ip *c);
|
||||
int model_parse(struct fpga_ip *c, json_t *cfg);
|
||||
|
||||
/** Destroy a model */
|
||||
int model_destroy(struct fpga_ip *c);
|
||||
|
@ -102,17 +102,17 @@ int model_destroy(struct fpga_ip *c);
|
|||
void model_dump(struct fpga_ip *c);
|
||||
|
||||
/** Add a new parameter to the model */
|
||||
void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direction dir, enum model_param_type type);
|
||||
void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type);
|
||||
|
||||
/** Remove an existing parameter by its name */
|
||||
int model_param_remove(struct fpga_ip *c, const char *name);
|
||||
int model_parameter_remove(struct fpga_ip *c, const char *name);
|
||||
|
||||
/** Read a model parameter.
|
||||
*
|
||||
* Note: the data type of the register is taken into account.
|
||||
* All datatypes are converted to double.
|
||||
*/
|
||||
int model_param_read(struct model_param *p, double *v);
|
||||
int model_parameter_read(struct model_parameter *p, double *v);
|
||||
|
||||
/** Update a model parameter.
|
||||
*
|
||||
|
@ -120,8 +120,8 @@ int model_param_read(struct model_param *p, double *v);
|
|||
* The double argument will be converted to the respective data type of the
|
||||
* GatewayIn/Out block.
|
||||
*/
|
||||
int model_param_write(struct model_param *p, double v);
|
||||
int model_parameter_write(struct model_parameter *p, double v);
|
||||
|
||||
int model_param_update(struct model_param *p, struct model_param *u);
|
||||
int model_parameter_update(struct model_parameter *p, struct model_parameter *u);
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <jansson.h>
|
||||
#include <xilinx/xaxis_switch.h>
|
||||
|
||||
#include "list.h"
|
||||
|
@ -41,7 +42,7 @@ int switch_init_paths(struct fpga_ip *c);
|
|||
|
||||
int switch_destroy(struct fpga_ip *c);
|
||||
|
||||
int switch_parse(struct fpga_ip *c);
|
||||
int switch_parse(struct fpga_ip *c, json_t *cfg);
|
||||
|
||||
int switch_connect(struct fpga_ip *c, struct fpga_ip *mi, struct fpga_ip *si);
|
||||
|
||||
|
|
|
@ -93,12 +93,8 @@ char * hist_dump(struct hist *h);
|
|||
/** Prints Matlab struct containing all infos to file. */
|
||||
int hist_dump_matlab(struct hist *h, FILE *f);
|
||||
|
||||
#ifdef WITH_JSON
|
||||
|
||||
/** Write the histogram in JSON format to fiel \p f. */
|
||||
int hist_dump_json(struct hist *h, FILE *f);
|
||||
|
||||
/** Build a libjansson / JSON object of the histogram. */
|
||||
json_t * hist_json(struct hist *h);
|
||||
|
||||
#endif /* WITH_JSON */
|
||||
|
|
|
@ -52,21 +52,13 @@ struct hook {
|
|||
void *_vd; /**< Private data for this hook. This pointer can be used to pass data between consecutive calls of the callback. */
|
||||
|
||||
int priority; /**< A priority to change the order of execution within one type of hook. */
|
||||
|
||||
json_t *cfg; /**< A JSON object containing the configuration of the hook. */
|
||||
};
|
||||
|
||||
/** Save references to global nodes, paths and settings */
|
||||
int hook_init(struct hook *h, struct hook_type *vt, struct path *p);
|
||||
|
||||
/** Parse a single hook.
|
||||
*
|
||||
* A hook definition is composed of the hook name and optional parameters
|
||||
* seperated by a colon.
|
||||
*
|
||||
* Examples:
|
||||
* "print:stdout"
|
||||
*/
|
||||
int hook_parse(struct hook *h, config_setting_t *cfg);
|
||||
|
||||
int hook_parse(struct hook *h, json_t *cfg);
|
||||
int hook_parse_cli(struct hook *h, int argc, char *argv[]);
|
||||
|
||||
int hook_destroy(struct hook *h);
|
||||
|
@ -100,4 +92,4 @@ int hook_cmp_priority(const void *a, const void *b);
|
|||
* hooks = [ "print" ]
|
||||
* }
|
||||
*/
|
||||
int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *p);
|
||||
int hook_parse_list(struct list *list, json_t *cfg, struct path *p);
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
/* Forward declarations */
|
||||
struct hook;
|
||||
|
@ -49,7 +49,7 @@ struct hook_type {
|
|||
|
||||
size_t size; /**< Size of allocation for struct hook::_vd */
|
||||
|
||||
int (*parse)(struct hook *h, config_setting_t *cfg);
|
||||
int (*parse)(struct hook *h, json_t *cfg);
|
||||
int (*parse_cli)(struct hook *h, int argc, char *argv[]);
|
||||
|
||||
int (*init)(struct hook *h); /**< Called before path is started to parseHOOK_DESTROYs. */
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
#include <netlink/route/qdisc.h>
|
||||
#include <netlink/route/classifier.h>
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
typedef uint32_t tc_hdl_t;
|
||||
|
||||
|
@ -43,12 +43,12 @@ struct interface;
|
|||
|
||||
/** Parse network emulator (netem) settings.
|
||||
*
|
||||
* @param cfg A libconfig object containing the settings.
|
||||
* @param cfg A jansson object containing the settings.
|
||||
* @param[out] ne A pointer to a libnl3 qdisc object where setting will be written to.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **ne);
|
||||
int tc_parse(struct rtnl_qdisc **ne, json_t *cfg);
|
||||
|
||||
/** Print network emulator (netem) setting into buffer.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** Logging routines that depend on libconfig.
|
||||
/** Logging routines that depend on jansson.
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
|
@ -25,14 +25,13 @@
|
|||
|
||||
struct log;
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
/** Parse logging configuration. */
|
||||
int log_parse(struct log *l, config_setting_t *cfg);
|
||||
int log_parse(struct log *l, json_t *cfg);
|
||||
|
||||
/** Print configuration error and exit. */
|
||||
void cerror(config_setting_t *cfg, const char *fmt, ...)
|
||||
void jerror(json_error_t *err, const char *fmt, ...)
|
||||
__attribute__ ((format(printf, 2, 3)));
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "stats.h"
|
||||
#include "common.h"
|
||||
|
@ -87,7 +87,7 @@ struct mapping {
|
|||
|
||||
int mapping_init(struct mapping *m);
|
||||
|
||||
int mapping_parse(struct mapping *m, config_setting_t *cfg);
|
||||
int mapping_parse(struct mapping *m, json_t *cfg);
|
||||
|
||||
int mapping_check(struct mapping *m);
|
||||
|
||||
|
@ -95,6 +95,6 @@ int mapping_destroy(struct mapping *m);
|
|||
|
||||
int mapping_remap(struct mapping *m, struct sample *orig, struct sample *remapped, struct stats *s);
|
||||
|
||||
int mapping_entry_parse(struct mapping_entry *e, config_setting_t *cfg);
|
||||
int mapping_entry_parse(struct mapping_entry *e, json_t *cfg);
|
||||
|
||||
int mapping_entry_parse_str(struct mapping_entry *e, const char *str);
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "node_type.h"
|
||||
#include "sample.h"
|
||||
|
@ -58,17 +58,19 @@ struct node
|
|||
|
||||
struct node_type *_vt; /**< Virtual functions (C++ OOP style) */
|
||||
void *_vd; /**< Virtual data (used by struct node::_vt functions) */
|
||||
|
||||
json_t *cfg; /**< A JSON object containing the configuration of the node. */
|
||||
};
|
||||
|
||||
int node_init(struct node *n, struct node_type *vt);
|
||||
|
||||
/** Parse settings of a node.
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param cfg A JSON object containing the configuration of the node.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int node_parse(struct node *n, config_setting_t *cfg);
|
||||
int node_parse(struct node *n, json_t *cfg, const char *name);
|
||||
|
||||
/** Parse settings of a node from cmdline. */
|
||||
int node_parse_cli(struct node *n, int argc, char *argv[]);
|
||||
|
@ -128,10 +130,10 @@ int node_write(struct node *n, struct sample *smps[], unsigned cnt);
|
|||
* out = [ "sintef", "scedu" ]
|
||||
* out = "acs"
|
||||
*
|
||||
* @param cfg The libconfig object handle for "out".
|
||||
* @param cfg A JSON array or string. See examples above.
|
||||
* @param nodes The nodes will be added to this list.
|
||||
* @param all This list contains all valid nodes.
|
||||
*/
|
||||
int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all);
|
||||
int node_parse_list(struct list *list, json_t *cfg, struct list *all);
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "common.h"
|
||||
|
@ -78,11 +78,11 @@ struct node_type {
|
|||
/** Parse node connection details.
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @param cfg A libconfig object pointing to the node.
|
||||
* @param cfg A JSON object containing the configuration of the node.
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int (*parse)(struct node *n, config_setting_t *cfg);
|
||||
int (*parse)(struct node *n, json_t *cfg);
|
||||
|
||||
/** Parse node from command line arguments. */
|
||||
int (*parse_cli)(struct node *n, int argc, char *argv[]);
|
||||
|
@ -118,10 +118,10 @@ struct node_type {
|
|||
* Indexes used to address @p m will wrap around after len messages.
|
||||
* Some node-types might only support to receive one message at a time.
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @param smps An array of pointers to memory blocks where the function should store received samples.
|
||||
* @param cnt The number of messages which should be received.
|
||||
* @return The number of messages actually received.
|
||||
* @param n A pointer to the node object.
|
||||
* @param smps An array of pointers to memory blocks where the function should store received samples.
|
||||
* @param cnt The number of messages which should be received.
|
||||
* @return The number of messages actually received.
|
||||
*/
|
||||
int (*read) (struct node *n, struct sample *smps[], unsigned cnt);
|
||||
|
||||
|
@ -132,10 +132,10 @@ struct node_type {
|
|||
* The messages have to be stored in a circular buffer / array m.
|
||||
* So the indexes will wrap around after len.
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @param smps An array of pointers to memory blocks where samples read from.
|
||||
* @param cnt The number of messages which should be sent.
|
||||
* @return The number of messages actually sent.
|
||||
* @param n A pointer to the node object.
|
||||
* @param smps An array of pointers to memory blocks where samples read from.
|
||||
* @param cnt The number of messages which should be sent.
|
||||
* @return The number of messages actually sent.
|
||||
*/
|
||||
int (*write)(struct node *n, struct sample *smps[], unsigned cnt);
|
||||
|
||||
|
@ -143,7 +143,7 @@ struct node_type {
|
|||
*
|
||||
* This is not supported by all node-types!
|
||||
*
|
||||
* @param n A pointer to the node object.
|
||||
* @param n A pointer to the node object.
|
||||
*/
|
||||
int (*reverse)(struct node *n);
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ struct file {
|
|||
AFILE *handle; /**< libc: stdio file handle. */
|
||||
|
||||
const char *mode; /**< libc: fopen() mode. */
|
||||
const char *fmt; /**< Format string for file name. */
|
||||
const char *format; /**< Format string for file name. */
|
||||
|
||||
char *uri; /**< Real file name. */
|
||||
} read, write;
|
||||
|
@ -78,7 +78,7 @@ struct file {
|
|||
char * file_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int file_parse(struct node *n, config_setting_t *cfg);
|
||||
int file_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::open */
|
||||
int file_start(struct node *n);
|
||||
|
|
|
@ -44,7 +44,7 @@ int fpga_init(struct super_node *sn);
|
|||
int fpga_deinit();
|
||||
|
||||
/** @see node_type::parse */
|
||||
int fpga_parse(struct node *n, config_setting_t *cfg);
|
||||
int fpga_parse(struct node *n, json_t *cfg);
|
||||
|
||||
struct fpga_card * fpga_lookup_card(const char *name);
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "queue_signalled.h"
|
||||
#include "pool.h"
|
||||
|
||||
|
@ -53,7 +51,7 @@ struct loopback {
|
|||
char * loopback_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int loopback_parse(struct node *n, config_setting_t *cfg);
|
||||
int loopback_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::open */
|
||||
int loopback_open(struct node *n);
|
||||
|
|
|
@ -50,7 +50,7 @@ struct nanomsg {
|
|||
char * nanomsg_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int nanomsg_parse(struct node *n, config_setting_t *cfg);
|
||||
int nanomsg_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::open */
|
||||
int nanomsg_start(struct node *n);
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#include <jansson.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "msg.h"
|
||||
#include "super_node.h"
|
||||
#include "node.h"
|
||||
|
||||
|
@ -77,7 +76,7 @@ int ngsi_init(struct super_node *sn);
|
|||
int ngsi_deinit();
|
||||
|
||||
/** @see node_type::parse */
|
||||
int ngsi_parse(struct node *n, config_setting_t *cfg);
|
||||
int ngsi_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::print */
|
||||
char * ngsi_print(struct node *n);
|
||||
|
|
|
@ -67,7 +67,7 @@ int opal_init(struct super_node *sn);
|
|||
int opal_deinit();
|
||||
|
||||
/** @see node_type::parse */
|
||||
int opal_parse(struct node *n, config_setting_t *cfg);
|
||||
int opal_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::print */
|
||||
char * opal_print(struct node *n);
|
||||
|
|
|
@ -51,7 +51,7 @@ struct shmem {
|
|||
char * shmem_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int shmem_parse(struct node *n, config_setting_t *cfg);
|
||||
int shmem_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::open */
|
||||
int shmem_open(struct node *n);
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "timing.h"
|
||||
|
||||
/* Forward declarations */
|
||||
|
@ -71,7 +69,7 @@ struct signal {
|
|||
char * signal_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int signal_parse(struct node *n, config_setting_t *cfg);
|
||||
int signal_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::open */
|
||||
int signal_open(struct node *n);
|
||||
|
|
|
@ -112,7 +112,7 @@ int socket_write(struct node *n, struct sample *smps[], unsigned cnt);
|
|||
int socket_read(struct node *n, struct sample *smps[], unsigned cnt);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int socket_parse(struct node *n, config_setting_t *cfg);
|
||||
int socket_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::print */
|
||||
char * socket_print(struct node *n);
|
||||
|
|
|
@ -55,7 +55,7 @@ struct test_rtt {
|
|||
char * test_rtt_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int test_rtt_parse(struct node *n, config_setting_t *cfg);
|
||||
int test_rtt_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::open */
|
||||
int test_rtt_start(struct node *n);
|
||||
|
|
|
@ -74,7 +74,7 @@ struct zeromq {
|
|||
char * zeromq_print(struct node *n);
|
||||
|
||||
/** @see node_type::parse */
|
||||
int zeromq_parse(struct node *n, config_setting_t *cfg);
|
||||
int zeromq_parse(struct node *n, json_t *cfg);
|
||||
|
||||
/** @see node_type::init */
|
||||
int zeromq_init();
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <pthread.h>
|
||||
#include <libconfig.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "queue.h"
|
||||
|
@ -83,6 +83,8 @@ struct path
|
|||
struct stats *stats; /**< Statistic counters. This is a pointer to the statistic hooks private data. */
|
||||
|
||||
struct super_node *super_node; /**< The super node this path belongs to. */
|
||||
|
||||
json_t *cfg; /**< A JSON object containing the configuration of the path. */
|
||||
};
|
||||
|
||||
/** Initialize internal data structures. */
|
||||
|
@ -140,12 +142,12 @@ int path_uses_node(struct path *p, struct node *n);
|
|||
|
||||
/** Parse a single path and add it to the global configuration.
|
||||
*
|
||||
* @param cfg A libconfig object pointing to the path
|
||||
* @param cfg A JSON object containing the configuration of the path.
|
||||
* @param p Pointer to the allocated memory for this path
|
||||
* @param nodes A linked list of all existing nodes
|
||||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes);
|
||||
int path_parse(struct path *p, json_t *cfg, struct list *nodes);
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -94,7 +94,7 @@ int plugin_init(struct plugin *p);
|
|||
|
||||
int plugin_destroy(struct plugin *p);
|
||||
|
||||
int plugin_parse(struct plugin *p, config_setting_t *cfg);
|
||||
int plugin_parse(struct plugin *p, json_t *cfg);
|
||||
|
||||
int plugin_load(struct plugin *p);
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#define _STATS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <jansson.h>
|
||||
|
||||
#include "hist.h"
|
||||
|
||||
|
@ -73,11 +74,7 @@ void stats_collect(struct stats_delta *s, struct sample *smps[], size_t cnt);
|
|||
|
||||
int stats_commit(struct stats *s, struct stats_delta *d);
|
||||
|
||||
#ifdef WITH_JSON
|
||||
#include <jansson.h>
|
||||
|
||||
json_t * stats_json(struct stats *s);
|
||||
#endif
|
||||
|
||||
void stats_reset(struct stats *s);
|
||||
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
/** Configuration file parser.
|
||||
*
|
||||
* The server program is configured by a single file.
|
||||
* This config file is parsed with a third-party library:
|
||||
* libconfig http://www.hyperrealm.com/libconfig/
|
||||
/** The super node object holding the state of the application.
|
||||
*
|
||||
* @file
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
|
@ -27,8 +23,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "api.h"
|
||||
#include "web.h"
|
||||
|
@ -57,8 +51,7 @@ struct super_node {
|
|||
|
||||
enum state state;
|
||||
|
||||
config_t cfg; /**< Pointer to configuration file */
|
||||
json_t *json; /**< JSON representation of the same config. */
|
||||
json_t *cfg; /**< JSON representation of the configuration. */
|
||||
};
|
||||
|
||||
/* Compatibility with libconfig < 1.5 */
|
||||
|
@ -82,7 +75,7 @@ int super_node_parse_uri(struct super_node *sn, const char *uri);
|
|||
* @retval 0 Success. Everything went well.
|
||||
* @retval <0 Error. Something went wrong.
|
||||
*/
|
||||
int super_node_parse(struct super_node *sn, config_setting_t *cfg);
|
||||
int super_node_parse_json(struct super_node *sn, json_t *cfg);
|
||||
|
||||
/** Check validity of super node configuration. */
|
||||
int super_node_check(struct super_node *sn);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "common.h"
|
||||
|
@ -60,4 +59,4 @@ int web_start(struct web *w);
|
|||
int web_stop(struct web *w);
|
||||
|
||||
/** Parse HTTPd and WebSocket related options */
|
||||
int web_parse(struct web *w, config_setting_t *lcs);
|
||||
int web_parse(struct web *w, json_t *cfg);
|
||||
|
|
|
@ -26,7 +26,6 @@ LIB = $(BUILDDIR)/$(LIB_NAME).so.$(LIB_ABI_VERSION)
|
|||
|
||||
WITH_WEB ?= 1
|
||||
WITH_API ?= 1
|
||||
WITH_JSON ?= 1
|
||||
|
||||
# Object files for libvillas
|
||||
LIB_SRCS += $(addprefix lib/kernel/, kernel.c rt.c) \
|
||||
|
@ -46,12 +45,6 @@ endif
|
|||
|
||||
LIB_PKGS += openssl libcurl
|
||||
|
||||
ifeq ($(WITH_JSON),1)
|
||||
LIB_SRCS += lib/formats/json.c
|
||||
LIB_PKGS += jansson
|
||||
LIB_CFLAGS += -DWITH_JSON
|
||||
endif
|
||||
|
||||
ifeq ($(WITH_WEB),1)
|
||||
-include lib/web/Makefile.inc
|
||||
endif
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
###################################################################################
|
||||
|
||||
ifndef WITH_JSON
|
||||
$(error API support requires JSON)
|
||||
endif
|
||||
|
||||
LIB_SRCS += lib/api.c
|
||||
LIB_SRCS += $(wildcard lib/api/*.c)
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "utils.h"
|
||||
#include "plugin.h"
|
||||
|
@ -30,9 +28,7 @@
|
|||
|
||||
static int api_config(struct api_action *h, json_t *args, json_t **resp, struct api_session *s)
|
||||
{
|
||||
config_setting_t *cfg_root = config_root_setting(&s->api->super_node->cfg);
|
||||
|
||||
*resp = cfg_root ? config_to_json(cfg_root) : json_object();
|
||||
*resp = s->api->super_node->cfg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ static int api_nodes(struct api_action *r, json_t *args, json_t **resp, struct a
|
|||
|
||||
/* Add all additional fields of node here.
|
||||
* This can be used for metadata */
|
||||
json_object_update(json_node, config_to_json(n->cfg));
|
||||
json_object_update(json_node, n->cfg);
|
||||
|
||||
json_array_append_new(json_nodes, json_node);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ static int api_paths(struct api_action *r, json_t *args, json_t **resp, struct a
|
|||
|
||||
/* Add all additional fields of node here.
|
||||
* This can be used for metadata */
|
||||
json_object_update(json_path, config_to_json(p->cfg));
|
||||
json_object_update(json_path, p->cfg);
|
||||
|
||||
json_array_append_new(json_paths, json_path);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,13 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "config_helper.h"
|
||||
#include "utils.h"
|
||||
|
||||
#ifdef WITH_JSON
|
||||
#ifdef WITH_LIBCONFIG
|
||||
|
||||
static int json_to_config_type(int type)
|
||||
{
|
||||
switch (type) {
|
||||
|
@ -139,24 +142,180 @@ int json_to_config(json_t *json, config_setting_t *parent)
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
#endif /* WITH_LIBCONFIG */
|
||||
|
||||
int config_read_cli(config_t *cfg, int argc, char *argv[])
|
||||
void json_object_extend_key_value(json_t *obj, const char *key, const char *value)
|
||||
{
|
||||
int ret;
|
||||
char *str = NULL;
|
||||
char *end, *cpy, *key1, *key2;
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
str = strcatf(&str, "%s", argv[i]);
|
||||
double real;
|
||||
long integer;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
json_t *arr, *new, *existing, *subobj;
|
||||
|
||||
config_set_auto_convert(cfg, 1);
|
||||
/* Is the key pointing to an object? */
|
||||
subobj = obj;
|
||||
cpy = strdup(key);
|
||||
|
||||
ret = config_read_string(cfg, str);
|
||||
key1 = strtok(cpy, ".");
|
||||
key2 = strtok(NULL, ".");
|
||||
|
||||
free(str);
|
||||
while (key1 && key2) {
|
||||
existing = json_object_get(subobj, key1);
|
||||
if (existing)
|
||||
subobj = existing;
|
||||
else {
|
||||
new = json_object();
|
||||
json_object_set(subobj, key1, new);
|
||||
|
||||
return ret != CONFIG_TRUE;
|
||||
subobj = new;
|
||||
}
|
||||
|
||||
key1 = key2;
|
||||
key2 = strtok(NULL, ".");
|
||||
}
|
||||
|
||||
/* Try to parse as integer */
|
||||
integer = strtol(value, &end, 0);
|
||||
if (*end == 0) {
|
||||
new = json_integer(integer);
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* Try to parse as floating point */
|
||||
real = strtod(value, &end);
|
||||
if (*end == 0) {
|
||||
new = json_real(real);
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* Try to parse special types */
|
||||
if (!strcmp(value, "true")) {
|
||||
new = json_true();
|
||||
goto success;
|
||||
}
|
||||
|
||||
if (!strcmp(value, "false")) {
|
||||
new = json_false();
|
||||
goto success;
|
||||
}
|
||||
|
||||
if (!strcmp(value, "null")) {
|
||||
new = json_null();
|
||||
goto success;
|
||||
}
|
||||
|
||||
/* Fallback to string */
|
||||
new = json_string(value);
|
||||
|
||||
success:
|
||||
/* Does the key already exist?
|
||||
* If yes, transform to array. */
|
||||
existing = json_object_get(subobj, key1);
|
||||
if (existing) {
|
||||
if (json_is_array(existing))
|
||||
arr = existing;
|
||||
else {
|
||||
arr = json_array();
|
||||
json_object_set(subobj, key1, arr);
|
||||
json_array_append(arr, existing);
|
||||
}
|
||||
|
||||
json_array_append(arr, new);
|
||||
}
|
||||
else
|
||||
json_object_set(subobj, key1, new);
|
||||
}
|
||||
|
||||
json_t * json_load_cli(int argc, char *argv[])
|
||||
{
|
||||
char *opt;
|
||||
char *key = NULL;
|
||||
char *value = NULL;
|
||||
char *sep, *cpy;
|
||||
|
||||
json_t *json = json_object();
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
opt = argv[i];
|
||||
|
||||
/* Long Option */
|
||||
if (opt[0] == '-' && opt[1] == '-') {
|
||||
/* Option without value? Abort. */
|
||||
if (key != NULL)
|
||||
return NULL;
|
||||
|
||||
key = opt + 2;
|
||||
|
||||
/* Does this option has the form "--option=value"? */
|
||||
sep = strchr(key, '=');
|
||||
if (sep) {
|
||||
cpy = strdup(key);
|
||||
|
||||
key = strtok(cpy, "=");
|
||||
value = strtok(NULL, "");
|
||||
|
||||
json_object_extend_key_value(json, key, value);
|
||||
|
||||
free(cpy);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
/* Value */
|
||||
else {
|
||||
/* Value without key. Abort. */
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
value = opt;
|
||||
|
||||
json_object_extend_key_value(json, key, value);
|
||||
key = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
int json_object_extend(json_t *obj, json_t *merge)
|
||||
{
|
||||
const char *key;
|
||||
void *tmp;
|
||||
int ret;
|
||||
json_t *merge_value, *obj_value;
|
||||
|
||||
if (!json_is_object(obj) || !json_is_object(merge))
|
||||
return -1;
|
||||
|
||||
json_object_foreach_safe(merge, tmp, key, merge_value) {
|
||||
obj_value = json_object_get(obj, key);
|
||||
if (obj_value && json_is_object(obj_value))
|
||||
ret = json_object_extend(obj_value, merge_value);
|
||||
else
|
||||
ret = json_object_set(obj, key, merge_value);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_object_extend_str(json_t *obj, const char *str)
|
||||
{
|
||||
char *key, *value, *cpy;
|
||||
|
||||
cpy = strdup(str);
|
||||
|
||||
key = strtok(cpy, "=");
|
||||
value = strtok(NULL, "");
|
||||
|
||||
if (!key || !value)
|
||||
return -1;
|
||||
|
||||
json_object_extend_key_value(obj, key, value);
|
||||
|
||||
free(cpy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -55,48 +55,59 @@ int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg)
|
||||
int fpga_card_parse(struct fpga_card *c, json_t *cfg, const char *name)
|
||||
{
|
||||
int ret;
|
||||
const char *slot, *id, *err;
|
||||
config_setting_t *cfg_ips, *cfg_slot, *cfg_id;
|
||||
|
||||
c->name = config_setting_name(cfg);
|
||||
json_t *cfg_ips;
|
||||
json_t *cfg_slot = NULL;
|
||||
json_t *cfg_id = NULL;
|
||||
json_error_t err;
|
||||
|
||||
config_setting_lookup_int(cfg, "affinity", &c->affinity);
|
||||
config_setting_lookup_bool(cfg, "do_reset", &c->do_reset);
|
||||
c->name = strdup(name);
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: b, s?: o, s?: o, s: o }"
|
||||
"affinity", &c->affinity,
|
||||
"do_reset", &c->do_reset,
|
||||
"slot", &cfg_slot,
|
||||
"id", &cfg_id,
|
||||
"ips", &cfg_ips
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse FPGA vard configuration");
|
||||
|
||||
cfg_slot = config_setting_get_member(cfg, "slot");
|
||||
if (cfg_slot) {
|
||||
slot = config_setting_get_string(cfg_slot);
|
||||
const char *err, *slot;
|
||||
|
||||
slot = json_string_value(cfg_slot);
|
||||
if (slot) {
|
||||
ret = pci_device_parse_slot(&c->filter, slot, &err);
|
||||
if (ret)
|
||||
cerror(cfg_slot, "Failed to parse PCI slot: %s", err);
|
||||
error("Failed to parse PCI slot: %s", err);
|
||||
}
|
||||
else
|
||||
cerror(cfg_slot, "PCI slot must be a string");
|
||||
error("PCI slot must be a string");
|
||||
}
|
||||
|
||||
cfg_id = config_setting_get_member(cfg, "id");
|
||||
if (cfg_id) {
|
||||
id = config_setting_get_string(cfg_id);
|
||||
const char *err, *id;
|
||||
|
||||
id = json_string_value(cfg_id);
|
||||
if (id) {
|
||||
ret = pci_device_parse_id(&c->filter, (char*) id, &err);
|
||||
if (ret)
|
||||
cerror(cfg_id, "Failed to parse PCI id: %s", err);
|
||||
error("Failed to parse PCI id: %s", err);
|
||||
}
|
||||
else
|
||||
cerror(cfg_slot, "PCI ID must be a string");
|
||||
error("PCI ID must be a string");
|
||||
}
|
||||
|
||||
cfg_ips = config_setting_get_member(cfg, "ips");
|
||||
if (!cfg_ips)
|
||||
cerror(cfg, "FPGA configuration is missing ips section");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_ips); i++) {
|
||||
config_setting_t *cfg_ip = config_setting_get_elem(cfg_ips, i);
|
||||
if (!json_is_object(cfg_ips))
|
||||
error("FPGA card IPs section must be an object");
|
||||
|
||||
const char *name_ip;
|
||||
json_t *cfg_ip;
|
||||
json_object_foreach(cfg_ips, name_ip, cfg_ip) {
|
||||
const char *vlnv;
|
||||
|
||||
struct fpga_ip_type *vt;
|
||||
|
@ -104,45 +115,45 @@ int fpga_card_parse(struct fpga_card *c, config_setting_t *cfg)
|
|||
|
||||
ip->card = c;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "vlnv", &vlnv))
|
||||
cerror(cfg, "FPGA IP core %s is missing the VLNV identifier", c->name);
|
||||
ret = json_unpack_ex(cfg_ip, &err, 0, "{ s: s }", "vlnv", &vlnv);
|
||||
if (ret)
|
||||
error("Failed to parse FPGA IP '%s' of card '%s'", name_ip, name);
|
||||
|
||||
vt = fpga_ip_type_lookup(vlnv);
|
||||
if (!vt)
|
||||
cerror(cfg, "FPGA IP core VLNV identifier '%s' is invalid", vlnv);
|
||||
error("FPGA IP core VLNV identifier '%s' is invalid", vlnv);
|
||||
|
||||
ret = fpga_ip_init(ip, vt);
|
||||
if (ret)
|
||||
error("Failed to initalize FPGA IP core");
|
||||
|
||||
ret = fpga_ip_parse(ip, cfg_ip);
|
||||
ret = fpga_ip_parse(ip, cfg_ip, name_ip);
|
||||
if (ret)
|
||||
cerror(cfg_ip, "Failed to parse FPGA IP core");
|
||||
error("Failed to parse FPGA IP core");
|
||||
|
||||
list_push(&c->ips, ip);
|
||||
}
|
||||
|
||||
c->cfg = cfg;
|
||||
c->state = STATE_PARSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fpga_card_parse_list(struct list *cards, config_setting_t *cfg)
|
||||
int fpga_card_parse_list(struct list *cards, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!config_setting_is_group(cfg))
|
||||
cerror(cfg, "FPGA configuration section must be a group");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg); i++) {
|
||||
config_setting_t *cfg_fpga = config_setting_get_elem(cfg, i);
|
||||
if (!json_is_object(cfg))
|
||||
error("FPGA card configuration section must be a JSON object");
|
||||
|
||||
const char *name;
|
||||
json_t *cfg_fpga;
|
||||
json_object_foreach(cfg, name, cfg_fpga) {
|
||||
struct fpga_card *c = alloc(sizeof(struct fpga_card));
|
||||
|
||||
ret = fpga_card_parse(c, cfg_fpga);
|
||||
ret = fpga_card_parse(c, cfg_fpga, name);
|
||||
if (ret)
|
||||
cerror(cfg_fpga, "Failed to parse FPGA card configuration");
|
||||
error("Failed to parse FPGA card configuration");
|
||||
|
||||
list_push(cards, c);
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "log_config.h"
|
||||
#include "log.h"
|
||||
#include "plugin.h"
|
||||
|
@ -46,34 +44,33 @@ int fpga_ip_init(struct fpga_ip *c, struct fpga_ip_type *vt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int fpga_ip_parse(struct fpga_ip *c, config_setting_t *cfg)
|
||||
int fpga_ip_parse(struct fpga_ip *c, json_t *cfg, const char *name)
|
||||
{
|
||||
int ret;
|
||||
long long baseaddr;
|
||||
int ret, baseaddr = -1;
|
||||
|
||||
assert(c->state != STATE_STARTED && c->state != STATE_DESTROYED);
|
||||
|
||||
c->cfg = cfg;
|
||||
c->name = strdup(name);
|
||||
c->baseaddr = -1;
|
||||
c->irq = -1;
|
||||
c->port = -1;
|
||||
|
||||
c->name = config_setting_name(cfg);
|
||||
if (!c->name)
|
||||
cerror(cfg, "IP is missing a name");
|
||||
json_error_t err;
|
||||
|
||||
/* Common settings */
|
||||
if (config_setting_lookup_int64(cfg, "baseaddr", &baseaddr))
|
||||
c->baseaddr = baseaddr;
|
||||
else
|
||||
c->baseaddr = -1;
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i, s?: i }",
|
||||
"baseaddr", &baseaddr,
|
||||
"irq", &c->irq,
|
||||
"port", &c->port
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration for FPGA IP '%s'", name);
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "irq", &c->irq))
|
||||
c->irq = -1;
|
||||
if (!config_setting_lookup_int(cfg, "port", &c->port))
|
||||
c->port = -1;
|
||||
c->baseaddr = baseaddr;
|
||||
|
||||
/* Type sepecific settings */
|
||||
ret = c->_vt && c->_vt->parse ? c->_vt->parse(c) : 0;
|
||||
ret = c->_vt && c->_vt->parse ? c->_vt->parse(c, cfg) : 0;
|
||||
if (ret)
|
||||
error("Failed to parse settings for IP core '%s'", c->name);
|
||||
error("Failed to parse settings for IP core '%s'", name);
|
||||
|
||||
c->state = STATE_PARSED;
|
||||
|
||||
|
|
|
@ -13,33 +13,40 @@
|
|||
#include "fpga/card.h"
|
||||
#include "fpga/ips/dft.h"
|
||||
|
||||
int dft_parse(struct fpga_ip *c)
|
||||
int dft_parse(struct fpga_ip *c, json_t *cfg)
|
||||
{
|
||||
struct dft *dft = c->_vd;
|
||||
|
||||
config_setting_t *cfg_harms;
|
||||
int ret;
|
||||
|
||||
if (!config_setting_lookup_int(c->cfg, "period", &dft->period))
|
||||
cerror(c->cfg, "DFT IP core requires 'period' setting");
|
||||
json_t *cfg_harms;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_lookup_int(c->cfg, "decimation", &dft->decimation))
|
||||
cerror(c->cfg, "DFT IP core requires 'decimation' setting");
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: o }",
|
||||
"period", &dft->period,
|
||||
"decimation", &dft->decimation,
|
||||
"harmonics", &cfg_harms
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
||||
|
||||
cfg_harms = config_setting_get_member(c->cfg, "harmonics");
|
||||
if (!cfg_harms)
|
||||
cerror(c->cfg, "DFT IP core requires 'harmonics' setting!");
|
||||
if (!json_is_array(cfg_harms))
|
||||
error("DFT IP core requires 'harmonics' to be an array of integers!");
|
||||
|
||||
if (!config_setting_is_array(cfg_harms))
|
||||
cerror(c->cfg, "DFT IP core requires 'harmonics' to be an array of integers!");
|
||||
|
||||
dft->num_harmonics = config_setting_length(cfg_harms);
|
||||
dft->num_harmonics = json_array_size(cfg_harms);
|
||||
if (dft->num_harmonics <= 0)
|
||||
cerror(cfg_harms, "DFT IP core requires 'harmonics' to contain at least 1 integer!");
|
||||
error("DFT IP core requires 'harmonics' to contain at least 1 value!");
|
||||
|
||||
dft->fharmonics = alloc(sizeof(float) * dft->num_harmonics);
|
||||
|
||||
for (int i = 0; i < dft->num_harmonics; i++)
|
||||
dft->fharmonics[i] = (float) config_setting_get_int_elem(cfg_harms, i) / dft->period;
|
||||
size_t index;
|
||||
json_t *cfg_harm;
|
||||
json_array_foreach(cfg_harms, index, cfg_harm) {
|
||||
if (!json_is_real(cfg_harm))
|
||||
error("DFT IP core requires all 'harmonics' values to be of floating point type");
|
||||
|
||||
dft->fharmonics[index] = (float) json_number_value(cfg_harm) / dft->period;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -91,16 +91,21 @@ ssize_t fifo_read(struct fpga_ip *c, char *buf, size_t len)
|
|||
return nextlen;
|
||||
}
|
||||
|
||||
int fifo_parse(struct fpga_ip *c)
|
||||
int fifo_parse(struct fpga_ip *c, json_t *cfg)
|
||||
{
|
||||
struct fifo *fifo = c->_vd;
|
||||
|
||||
int baseaddr_axi4;
|
||||
int baseaddr_axi4 = -1, ret;
|
||||
|
||||
if (config_setting_lookup_int(c->cfg, "baseaddr_axi4", &baseaddr_axi4))
|
||||
fifo->baseaddr_axi4 = baseaddr_axi4;
|
||||
else
|
||||
fifo->baseaddr_axi4 = -1;
|
||||
json_error_t err;
|
||||
|
||||
fifo->baseaddr_axi4 = -1;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }", "baseaddr_axi4", &baseaddr_axi4);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
||||
|
||||
fifo->baseaddr_axi4 = baseaddr_axi4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "fpga/card.h"
|
||||
#include "fpga/ips/model.h"
|
||||
|
||||
static int model_param_destroy(struct model_param *p)
|
||||
static int model_parameter_destroy(struct model_parameter *p)
|
||||
{
|
||||
free(p->name);
|
||||
|
||||
|
@ -64,7 +64,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter
|
|||
if (length < 4)
|
||||
break; /* block is to small to describe a gateway */
|
||||
|
||||
struct model_param *e, *p = alloc(sizeof(struct model_param));
|
||||
struct model_parameter *e, *p = alloc(sizeof(struct model_parameter));
|
||||
|
||||
p->name = copy_string(3);
|
||||
p->default_value.flt = *((float *) &data[1]);
|
||||
|
@ -75,7 +75,7 @@ static int model_xsg_map_parse(uint32_t *map, size_t len, struct list *parameter
|
|||
|
||||
e = list_lookup(parameters, p->name);
|
||||
if (e)
|
||||
model_param_update(e, p);
|
||||
model_parameter_update(e, p);
|
||||
else
|
||||
list_push(parameters, p);
|
||||
break;
|
||||
|
@ -133,28 +133,40 @@ static int model_xsg_map_read(uint32_t *map, size_t len, void *baseaddr)
|
|||
return i;
|
||||
}
|
||||
|
||||
int model_parse(struct fpga_ip *c)
|
||||
int model_parse(struct fpga_ip *c, json_t *cfg)
|
||||
{
|
||||
struct model *m = c->_vd;
|
||||
|
||||
config_setting_t *cfg_params, *cfg_param;
|
||||
int ret;
|
||||
|
||||
json_t *cfg_params;
|
||||
json_error_t err;
|
||||
|
||||
if (strcmp(c->vlnv.library, "hls") == 0)
|
||||
m->type = MODEL_TYPE_HLS;
|
||||
else if (strcmp(c->vlnv.library, "sysgen") == 0)
|
||||
m->type = MODEL_TYPE_XSG;
|
||||
else
|
||||
cerror(c->cfg, "Invalid model type: %s", c->vlnv.library);
|
||||
error("Unsupported model type: %s", c->vlnv.library);
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "parameters", &cfg_params);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
||||
|
||||
cfg_params = config_setting_get_member(c->cfg, "parameters");
|
||||
if (cfg_params) {
|
||||
for (int i = 0; i < config_setting_length(cfg_params); i++) {
|
||||
cfg_param = config_setting_get_elem(cfg_params, i);
|
||||
if (!json_is_object(cfg_params))
|
||||
error("Setting 'parameters' must be a JSON object");
|
||||
|
||||
struct model_param *p = alloc(sizeof(struct model_param));
|
||||
const char *name;
|
||||
json_t *value;
|
||||
json_object_foreach(cfg_params, name, value) {
|
||||
if (!json_is_real(value))
|
||||
error("Parameters of FPGA IP '%s' must be of type floating point", c->name);
|
||||
|
||||
p->name = config_setting_name(cfg_param);
|
||||
p->default_value.flt = config_setting_get_float(cfg_param);
|
||||
struct model_parameter *p = alloc(sizeof(struct model_parameter));
|
||||
|
||||
p->name = strdup(name);
|
||||
p->default_value.flt = json_real_value(value);
|
||||
|
||||
list_push(&m->parameters, p);
|
||||
}
|
||||
|
@ -206,12 +218,12 @@ int model_init(struct fpga_ip *c)
|
|||
|
||||
/* Set default values for parameters */
|
||||
for (size_t i = 0; i < list_length(&m->parameters); i++) {
|
||||
struct model_param *p = list_at(&m->parameters, i);
|
||||
struct model_parameter *p = list_at(&m->parameters, i);
|
||||
|
||||
p->ip = c;
|
||||
|
||||
if (p->direction == MODEL_PARAM_IN) {
|
||||
model_param_write(p, p->default_value.flt);
|
||||
if (p->direction == MODEL_PARAMETER_IN) {
|
||||
model_parameter_write(p, p->default_value.flt);
|
||||
info("Set parameter '%s' updated to default value: %f", p->name, p->default_value.flt);
|
||||
}
|
||||
}
|
||||
|
@ -226,7 +238,7 @@ int model_destroy(struct fpga_ip *c)
|
|||
{
|
||||
struct model *m = c->_vd;
|
||||
|
||||
list_destroy(&m->parameters, (dtor_cb_t) model_param_destroy, true);
|
||||
list_destroy(&m->parameters, (dtor_cb_t) model_parameter_destroy, true);
|
||||
list_destroy(&m->infos, (dtor_cb_t) model_info_destroy, true);
|
||||
|
||||
if (m->xsg.map != NULL)
|
||||
|
@ -245,9 +257,9 @@ void model_dump(struct fpga_ip *c)
|
|||
{ INDENT
|
||||
info("Parameters:");
|
||||
for (size_t i = 0; i < list_length(&m->parameters); i++) { INDENT
|
||||
struct model_param *p = list_at(&m->parameters, i);
|
||||
struct model_parameter *p = list_at(&m->parameters, i);
|
||||
|
||||
if (p->direction == MODEL_PARAM_IN)
|
||||
if (p->direction == MODEL_PARAMETER_IN)
|
||||
info("%#jx: %s (%s) = %.3f %s %u",
|
||||
p->offset,
|
||||
p->name,
|
||||
|
@ -256,7 +268,7 @@ void model_dump(struct fpga_ip *c)
|
|||
param_type[p->type],
|
||||
p->binpt
|
||||
);
|
||||
else if (p->direction == MODEL_PARAM_OUT)
|
||||
else if (p->direction == MODEL_PARAMETER_OUT)
|
||||
info("%#jx: %s (%s)",
|
||||
p->offset,
|
||||
p->name,
|
||||
|
@ -273,52 +285,52 @@ void model_dump(struct fpga_ip *c)
|
|||
}
|
||||
}
|
||||
|
||||
int model_param_read(struct model_param *p, double *v)
|
||||
int model_parameter_read(struct model_parameter *p, double *v)
|
||||
{
|
||||
struct fpga_ip *c = p->ip;
|
||||
|
||||
union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
|
||||
union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset);
|
||||
|
||||
switch (p->type) {
|
||||
case MODEL_PARAM_TYPE_UFIX:
|
||||
case MODEL_PARAMETER_TYPE_UFIX:
|
||||
*v = (double) ptr->ufix / (1 << p->binpt);
|
||||
break;
|
||||
|
||||
case MODEL_PARAM_TYPE_FIX:
|
||||
case MODEL_PARAMETER_TYPE_FIX:
|
||||
*v = (double) ptr->fix / (1 << p->binpt);
|
||||
break;
|
||||
|
||||
case MODEL_PARAM_TYPE_FLOAT:
|
||||
case MODEL_PARAMETER_TYPE_FLOAT:
|
||||
*v = (double) ptr->flt;
|
||||
break;
|
||||
|
||||
case MODEL_PARAM_TYPE_BOOLEAN:
|
||||
case MODEL_PARAMETER_TYPE_BOOLEAN:
|
||||
*v = (double) ptr->ufix ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int model_param_write(struct model_param *p, double v)
|
||||
int model_parameter_write(struct model_parameter *p, double v)
|
||||
{
|
||||
struct fpga_ip *c = p->ip;
|
||||
|
||||
union model_param_value *ptr = (union model_param_value *) (c->card->map + c->baseaddr + p->offset);
|
||||
union model_parameter_value *ptr = (union model_parameter_value *) (c->card->map + c->baseaddr + p->offset);
|
||||
|
||||
switch (p->type) {
|
||||
case MODEL_PARAM_TYPE_UFIX:
|
||||
case MODEL_PARAMETER_TYPE_UFIX:
|
||||
ptr->ufix = (uint32_t) (v * (1 << p->binpt));
|
||||
break;
|
||||
|
||||
case MODEL_PARAM_TYPE_FIX:
|
||||
case MODEL_PARAMETER_TYPE_FIX:
|
||||
ptr->fix = (int32_t) (v * (1 << p->binpt));
|
||||
break;
|
||||
|
||||
case MODEL_PARAM_TYPE_FLOAT:
|
||||
case MODEL_PARAMETER_TYPE_FLOAT:
|
||||
ptr->flt = (float) v;
|
||||
break;
|
||||
|
||||
case MODEL_PARAM_TYPE_BOOLEAN:
|
||||
case MODEL_PARAMETER_TYPE_BOOLEAN:
|
||||
ptr->bol = (bool) v;
|
||||
break;
|
||||
}
|
||||
|
@ -326,10 +338,10 @@ int model_param_write(struct model_param *p, double v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direction dir, enum model_param_type type)
|
||||
void model_parameter_add(struct fpga_ip *c, const char *name, enum model_parameter_direction dir, enum model_parameter_type type)
|
||||
{
|
||||
struct model *m = c->_vd;
|
||||
struct model_param *p = alloc(sizeof(struct model_param));
|
||||
struct model_parameter *p = alloc(sizeof(struct model_parameter));
|
||||
|
||||
p->name = strdup(name);
|
||||
p->type = type;
|
||||
|
@ -338,10 +350,10 @@ void model_param_add(struct fpga_ip *c, const char *name, enum model_param_direc
|
|||
list_push(&m->parameters, p);
|
||||
}
|
||||
|
||||
int model_param_remove(struct fpga_ip *c, const char *name)
|
||||
int model_parameter_remove(struct fpga_ip *c, const char *name)
|
||||
{
|
||||
struct model *m = c->_vd;
|
||||
struct model_param *p;
|
||||
struct model_parameter *p;
|
||||
|
||||
p = list_lookup(&m->parameters, name);
|
||||
if (!p)
|
||||
|
@ -352,7 +364,7 @@ int model_param_remove(struct fpga_ip *c, const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int model_param_update(struct model_param *p, struct model_param *u)
|
||||
int model_parameter_update(struct model_parameter *p, struct model_parameter *u)
|
||||
{
|
||||
if (strcmp(p->name, u->name) != 0)
|
||||
return -1;
|
||||
|
|
|
@ -88,43 +88,41 @@ int switch_destroy(struct fpga_ip *c)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int switch_parse(struct fpga_ip *c)
|
||||
int switch_parse(struct fpga_ip *c, json_t *cfg)
|
||||
{
|
||||
struct fpga_card *f = c->card;
|
||||
struct sw *sw = c->_vd;
|
||||
|
||||
int ret;
|
||||
size_t index;
|
||||
json_error_t err;
|
||||
json_t *cfg_path, *cfg_paths = NULL;
|
||||
|
||||
list_init(&sw->paths);
|
||||
|
||||
config_setting_t *cfg_sw, *cfg_path;
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s?: o }",
|
||||
"num_ports", &sw->num_ports,
|
||||
"paths", &cfg_paths
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of FPGA IP '%s'", c->name);
|
||||
|
||||
if (!config_setting_lookup_int(c->cfg, "num_ports", &sw->num_ports))
|
||||
cerror(c->cfg, "Switch IP '%s' requires 'num_ports' option", c->name);
|
||||
|
||||
cfg_sw = config_setting_get_member(f->cfg, "paths");
|
||||
if (!cfg_sw)
|
||||
if (!cfg_paths)
|
||||
return 0; /* no switch config available */
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_sw); i++) {
|
||||
cfg_path = config_setting_get_elem(cfg_sw, i);
|
||||
if (!json_is_array(cfg_paths))
|
||||
error("Setting 'paths' of FPGA IP '%s' should be an array of JSON objects", c->name);
|
||||
|
||||
json_array_foreach(cfg_paths, index, cfg_path) {
|
||||
struct sw_path *p = alloc(sizeof(struct sw_path));
|
||||
int reverse;
|
||||
int reverse = 0;
|
||||
|
||||
if (!config_setting_lookup_bool(cfg_path, "reverse", &reverse))
|
||||
reverse = 0;
|
||||
|
||||
if (!config_setting_lookup_string(cfg_path, "in", &p->in) &&
|
||||
!config_setting_lookup_string(cfg_path, "from", &p->in) &&
|
||||
!config_setting_lookup_string(cfg_path, "src", &p->in) &&
|
||||
!config_setting_lookup_string(cfg_path, "source", &p->in))
|
||||
cerror(cfg_path, "Path is missing 'in' setting");
|
||||
|
||||
if (!config_setting_lookup_string(cfg_path, "out", &p->out) &&
|
||||
!config_setting_lookup_string(cfg_path, "to", &p->out) &&
|
||||
!config_setting_lookup_string(cfg_path, "dst", &p->out) &&
|
||||
!config_setting_lookup_string(cfg_path, "dest", &p->out) &&
|
||||
!config_setting_lookup_string(cfg_path, "sink", &p->out))
|
||||
cerror(cfg_path, "Path is missing 'out' setting");
|
||||
ret = json_unpack_ex(cfg_path, &err, 0, "{ s?: b, s: s, s: s }",
|
||||
"reverse", &reverse,
|
||||
"in", &p->in,
|
||||
"out", &p->out
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse path %zu of FPGA IP '%s'", index, c->name);
|
||||
|
||||
list_push(&sw->paths, p);
|
||||
|
||||
|
|
|
@ -212,7 +212,6 @@ char * hist_dump(struct hist *h)
|
|||
return buf;
|
||||
}
|
||||
|
||||
#ifdef WITH_JSON
|
||||
json_t * hist_json(struct hist *h)
|
||||
{
|
||||
json_t *json_buckets, *json_hist;
|
||||
|
@ -257,7 +256,6 @@ int hist_dump_json(struct hist *h, FILE *f)
|
|||
|
||||
return ret;
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
|
||||
int hist_dump_matlab(struct hist *h, FILE *f)
|
||||
{
|
||||
|
|
62
lib/hook.c
62
lib/hook.c
|
@ -21,7 +21,6 @@
|
|||
*********************************************************************************/
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "timing.h"
|
||||
#include "config.h"
|
||||
|
@ -54,18 +53,24 @@ int hook_init(struct hook *h, struct hook_type *vt, struct path *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int hook_parse(struct hook *h, config_setting_t *cfg)
|
||||
int hook_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
assert(h->state != STATE_DESTROYED);
|
||||
|
||||
config_setting_lookup_int(cfg, "priority", &h->priority);
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i }",
|
||||
"priority", &h->priority
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
ret = h->_vt->parse ? h->_vt->parse(h, cfg) : 0;
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
h->cfg = cfg;
|
||||
h->state = STATE_PARSED;
|
||||
|
||||
return 0;
|
||||
|
@ -83,20 +88,11 @@ int hook_parse_cli(struct hook *h, int argc, char *argv[])
|
|||
h->state = STATE_PARSED;
|
||||
}
|
||||
else {
|
||||
config_t cfg;
|
||||
config_setting_t *cfg_root;
|
||||
h->cfg = json_load_cli(argc, argv);
|
||||
if (!h->cfg)
|
||||
return -1;
|
||||
|
||||
config_init(&cfg);
|
||||
|
||||
ret = config_read_cli(&cfg, argc, argv);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
cfg_root = config_root_setting(&cfg);
|
||||
|
||||
ret = hook_parse(h, cfg_root);
|
||||
|
||||
out: config_destroy(&cfg);
|
||||
ret = hook_parse(h, h->cfg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -204,38 +200,36 @@ int hook_cmp_priority(const void *a, const void *b)
|
|||
return ha->priority - hb->priority;
|
||||
}
|
||||
|
||||
int hook_parse_list(struct list *list, config_setting_t *cfg, struct path *o)
|
||||
int hook_parse_list(struct list *list, json_t *cfg, struct path *o)
|
||||
{
|
||||
struct plugin *p;
|
||||
if (!json_is_array(cfg))
|
||||
error("Hooks must be configured as a list of objects");
|
||||
|
||||
int ret;
|
||||
const char *type;
|
||||
size_t index;
|
||||
json_t *cfg_hook;
|
||||
json_array_foreach(cfg, index, cfg_hook) {
|
||||
int ret;
|
||||
const char *type;
|
||||
struct plugin *p;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_is_list(cfg))
|
||||
cerror(cfg, "Hooks must be configured as a list of objects");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg); i++) {
|
||||
config_setting_t *cfg_hook = config_setting_get_elem(cfg, i);
|
||||
|
||||
if (!config_setting_is_group(cfg_hook))
|
||||
cerror(cfg_hook, "The 'hooks' setting must be an array of strings.");
|
||||
|
||||
if (!config_setting_lookup_string(cfg_hook, "type", &type))
|
||||
cerror(cfg_hook, "Missing setting 'type' for hook");
|
||||
ret = json_unpack_ex(cfg_hook, &err, 0, "{ s: s }", "type", &type);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse hook");
|
||||
|
||||
p = plugin_lookup(PLUGIN_TYPE_HOOK, type);
|
||||
if (!p)
|
||||
continue; /* We ignore all non hook settings in this libconfig object setting */
|
||||
jerror(&err, "Unkown hook type '%s'", type);
|
||||
|
||||
struct hook *h = alloc(sizeof(struct hook));
|
||||
|
||||
ret = hook_init(h, &p->hook, o);
|
||||
if (ret)
|
||||
cerror(cfg_hook, "Failed to initialize hook");
|
||||
jerror(&err, "Failed to initialize hook");
|
||||
|
||||
ret = hook_parse(h, cfg_hook);
|
||||
if (ret)
|
||||
cerror(cfg_hook, "Failed to parse hook configuration");
|
||||
jerror(&err, "Failed to parse hook configuration");
|
||||
|
||||
list_push(list, h);
|
||||
}
|
||||
|
|
|
@ -49,24 +49,28 @@ static int convert_init(struct hook *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int convert_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int convert_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct convert *p = h->_vd;
|
||||
|
||||
const char *mode;
|
||||
int ret;
|
||||
json_error_t err;
|
||||
const char *mode = NULL;
|
||||
|
||||
config_setting_lookup_float(cfg, "scale", &p->scale);
|
||||
config_setting_lookup_int64(cfg, "mask", &p->mask);
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "mode", &mode))
|
||||
cerror(cfg, "Missing setting 'mode' for hook '%s'", plugin_name(h->_vt));
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: F, s?: i, s: s }",
|
||||
"scale", &p->scale,
|
||||
"mask", &p->mask,
|
||||
"mode", &mode
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
if (!strcmp(mode, "fixed"))
|
||||
p->mode = TO_FIXED;
|
||||
else if (!strcmp(mode, "float"))
|
||||
p->mode = TO_FLOAT;
|
||||
else
|
||||
error("Invalid parameter '%s' for hook 'convert'", mode);
|
||||
error("Invalid 'mode' setting '%s' for hook '%s'", mode, plugin_name(h->_vt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -41,15 +41,18 @@ static int decimate_init(struct hook *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int decimate_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int decimate_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct decimate *p = h->_vd;
|
||||
|
||||
if (!cfg)
|
||||
error("Missing configuration for hook: '%s'", plugin_name(h->_vt));
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "ratio", &p->ratio))
|
||||
cerror(cfg, "Missing setting 'ratio' for hook '%s'", plugin_name(h->_vt));
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i }",
|
||||
"ratio", &p->ratio
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -51,15 +51,18 @@ static int map_destroy(struct hook *h)
|
|||
return mapping_destroy(&p->mapping);
|
||||
}
|
||||
|
||||
static int map_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int map_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
struct map *p = h->_vd;
|
||||
config_setting_t *cfg_mapping;
|
||||
json_error_t err;
|
||||
json_t *cfg_mapping;
|
||||
|
||||
cfg_mapping = config_setting_lookup(cfg, "mapping");
|
||||
if (!cfg_mapping || !config_setting_is_array(cfg_mapping))
|
||||
return -1;
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: o }",
|
||||
"map", &cfg_mapping
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
ret = mapping_parse(&p->mapping, cfg_mapping);
|
||||
if (ret)
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
|
||||
struct print {
|
||||
struct io output;
|
||||
struct io_format *format;
|
||||
|
||||
const char *uri;
|
||||
};
|
||||
|
||||
|
@ -38,7 +40,14 @@ static int print_init(struct hook *h)
|
|||
{
|
||||
struct print *p = h->_vd;
|
||||
|
||||
struct plugin *pl;
|
||||
|
||||
pl = plugin_lookup(PLUGIN_TYPE_FORMAT, "villas");
|
||||
if (!pl)
|
||||
return -1;
|
||||
|
||||
p->uri = NULL;
|
||||
p->format = &pl->io;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -46,22 +55,56 @@ static int print_init(struct hook *h)
|
|||
static int print_start(struct hook *h)
|
||||
{
|
||||
struct print *p = h->_vd;
|
||||
int ret;
|
||||
|
||||
return io_open(&p->output, p->uri, "w+");
|
||||
ret = io_init(&p->output, p->format, IO_FORMAT_ALL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = io_open(&p->output, p->uri, "w+");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_stop(struct hook *h)
|
||||
{
|
||||
struct print *p = h->_vd;
|
||||
int ret;
|
||||
|
||||
return io_close(&p->output);
|
||||
ret = io_close(&p->output);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = io_destroy(&p->output);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int print_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct print *p = h->_vd;
|
||||
struct plugin *pl;
|
||||
const char *format = NULL;
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
config_setting_lookup_string(cfg, "output", &p->uri);
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s }",
|
||||
"output", &p->uri
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
if (format) {
|
||||
pl = plugin_lookup(PLUGIN_TYPE_FORMAT, format);
|
||||
if (!pl)
|
||||
jerror(&err, "Invalid format '%s'", format);
|
||||
|
||||
p->format = &pl->io;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,12 +32,18 @@ struct shift {
|
|||
int offset;
|
||||
};
|
||||
|
||||
static int shift_seq_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int shift_seq_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct shift *p = h->_vd;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "offset", &p->offset))
|
||||
cerror(cfg, "Missing setting 'offset' for hook '%s'", plugin_name(h->_vt));
|
||||
json_error_t err;
|
||||
int ret;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i }",
|
||||
"offset", &p->offset
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -47,13 +47,22 @@ static int shift_ts_init(struct hook *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int shift_ts_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int shift_ts_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct shift_ts *p = h->_vd;
|
||||
double offset;
|
||||
const char *mode = NULL;
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
const char *mode;
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s: f }",
|
||||
"mode", &mode,
|
||||
"offset", &offset
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
if (config_setting_lookup_string(cfg, "mode", &mode)) {
|
||||
if (mode) {
|
||||
if (!strcmp(mode, "origin"))
|
||||
p->mode = SHIFT_ORIGIN;
|
||||
else if (!strcmp(mode, "received"))
|
||||
|
@ -61,13 +70,9 @@ static int shift_ts_parse(struct hook *h, config_setting_t *cfg)
|
|||
else if (!strcmp(mode, "sent"))
|
||||
p->mode = SHIFT_SENT;
|
||||
else
|
||||
cerror(cfg, "Invalid mode parameter '%s' for hook '%s'", mode, plugin_name(h->_vt));
|
||||
jerror(&err, "Invalid mode parameter '%s' for hook '%s'", mode, plugin_name(h->_vt));
|
||||
}
|
||||
|
||||
double offset;
|
||||
if (!config_setting_lookup_float(cfg, "offset", &offset))
|
||||
cerror(cfg, "Missing setting 'offset' for hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
p->offset = time_from_double(offset);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "hook.h"
|
||||
#include "plugin.h"
|
||||
#include "timing.h"
|
||||
|
@ -53,23 +51,33 @@ struct skip_first {
|
|||
};
|
||||
};
|
||||
|
||||
static int skip_first_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int skip_first_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct skip_first *p = h->_vd;
|
||||
|
||||
double seconds;
|
||||
|
||||
if (config_setting_lookup_float(cfg, "seconds", &seconds)) {
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: F }", "seconds", &seconds);
|
||||
if (!ret) {
|
||||
p->seconds.wait = time_from_double(seconds);
|
||||
p->mode = HOOK_SKIP_MODE_SECONDS;
|
||||
}
|
||||
else if (config_setting_lookup_int(cfg, "samples", &p->samples.wait)) {
|
||||
p->mode = HOOK_SKIP_MODE_SAMPLES;
|
||||
}
|
||||
else
|
||||
cerror(cfg, "Missing setting 'seconds' or 'samples' for hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i }", "samples", &p->samples.wait);
|
||||
if (!ret) {
|
||||
p->mode = HOOK_SKIP_MODE_SAMPLES;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int skip_first_restart(struct hook *h)
|
||||
|
|
|
@ -116,26 +116,35 @@ static int stats_collect_periodic(struct hook *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stats_collect_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int stats_collect_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct stats_collect *p = h->_vd;
|
||||
|
||||
const char *format, *uri;
|
||||
if (config_setting_lookup_string(cfg, "format", &format)) {
|
||||
int fmt;
|
||||
int ret, fmt;
|
||||
json_error_t err;
|
||||
|
||||
const char *format = NULL;
|
||||
const char *uri = NULL;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: s?: i, s?: s }"
|
||||
"format", &format,
|
||||
"verbose", &p->verbose,
|
||||
"warmup", &p->warmup,
|
||||
"buckets", &p->buckets,
|
||||
"output", &uri
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
if (format) {
|
||||
fmt = stats_lookup_format(format);
|
||||
if (fmt < 0)
|
||||
cerror(cfg, "Invalid statistic output format: %s", format);
|
||||
jerror(&err, "Invalid statistic output format: %s", format);
|
||||
|
||||
p->format = fmt;
|
||||
}
|
||||
|
||||
config_setting_lookup_bool(cfg, "verbose", &p->verbose);
|
||||
config_setting_lookup_int(cfg, "warmup", &p->warmup);
|
||||
config_setting_lookup_int(cfg, "buckets", &p->buckets);
|
||||
|
||||
if (config_setting_lookup_string(cfg, "output", &uri))
|
||||
if (uri)
|
||||
p->uri = strdup(uri);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -53,35 +53,45 @@ static int stats_send_init(struct hook *h)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stats_send_parse(struct hook *h, config_setting_t *cfg)
|
||||
static int stats_send_parse(struct hook *h, json_t *cfg)
|
||||
{
|
||||
struct stats_send *p = h->_vd;
|
||||
|
||||
assert(h->path && h->path->super_node);
|
||||
|
||||
const char *dest, *mode;
|
||||
const char *dest = NULL;
|
||||
const char *mode = NULL;
|
||||
|
||||
if (config_setting_lookup_string(cfg, "destination", &dest)) {
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s, s?: i }"
|
||||
"destination", &dest,
|
||||
"mode", &mode,
|
||||
"decimation", &p->decimation
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
if (dest) {
|
||||
assert(h->path);
|
||||
|
||||
p->dest = list_lookup(&h->path->super_node->nodes, dest);
|
||||
if (!p->dest)
|
||||
cerror(cfg, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt));
|
||||
jerror(&err, "Invalid destination node '%s' for hook '%s'", dest, plugin_name(h->_vt));
|
||||
}
|
||||
else
|
||||
cerror(cfg, "Missing setting 'destination' for hook '%s'", plugin_name(h->_vt));
|
||||
jerror(&err, "Missing setting 'destination' for hook '%s'", plugin_name(h->_vt));
|
||||
|
||||
if (config_setting_lookup_string(cfg, "mode", &mode)) {
|
||||
if (mode) {
|
||||
if (!strcmp(mode, "periodic"))
|
||||
p->mode = STATS_SEND_MODE_PERIODIC;
|
||||
else if (!strcmp(mode, "read"))
|
||||
p->mode = STATS_SEND_MODE_READ;
|
||||
else
|
||||
cerror(cfg, "Invalid value '%s' for setting 'mode' of hook '%s'", mode, plugin_name(h->_vt));
|
||||
jerror(&err, "Invalid value '%s' for setting 'mode' of hook '%s'", mode, plugin_name(h->_vt));
|
||||
}
|
||||
|
||||
config_setting_lookup_int(cfg, "decimation", &p->decimation);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,32 @@
|
|||
|
||||
#include "utils.h"
|
||||
|
||||
int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem)
|
||||
int tc_parse(struct rtnl_qdisc **netem, json_t *cfg)
|
||||
{
|
||||
const char *str;
|
||||
int val;
|
||||
int ret, val;
|
||||
|
||||
json_t *cfg_distribution = NULL;
|
||||
json_t *cfg_limit = NULL;
|
||||
json_t *cfg_delay = NULL;
|
||||
json_t *cfg_jitter = NULL;
|
||||
json_t *cfg_loss = NULL;
|
||||
json_t *cfg_duplicate = NULL;
|
||||
json_t *cfg_corruption = NULL;
|
||||
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: i, s?: i, s?: i, s?: i, s?: i, s?: i }",
|
||||
"distribution", &cfg_distribution,
|
||||
"limit", &cfg_limit,
|
||||
"delay", &cfg_delay,
|
||||
"jitter", &cfg_jitter,
|
||||
"loss", &cfg_loss,
|
||||
"duplicate", &cfg_duplicate,
|
||||
"corruption", &cfg_corruption
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse setting network emulation settings");
|
||||
|
||||
struct rtnl_qdisc *ne = rtnl_qdisc_alloc();
|
||||
if (!ne)
|
||||
|
@ -46,51 +68,67 @@ int tc_parse(config_setting_t *cfg, struct rtnl_qdisc **netem)
|
|||
|
||||
rtnl_tc_set_kind(TC_CAST(ne), "netem");
|
||||
|
||||
if (config_setting_lookup_string(cfg, "distribution", &str)) {
|
||||
if (cfg_distribution) {
|
||||
str = json_string_value(cfg_distribution);
|
||||
if (!str)
|
||||
error("Setting 'distribution' must be a JSON string");
|
||||
|
||||
if (rtnl_netem_set_delay_distribution(ne, str))
|
||||
cerror(cfg, "Invalid delay distribution '%s' in netem config", str);
|
||||
error("Invalid delay distribution '%s' in netem config", str);
|
||||
}
|
||||
|
||||
if (config_setting_lookup_int(cfg, "limit", &val)) {
|
||||
if (val <= 0)
|
||||
cerror(cfg, "Invalid value '%d' for limit setting", val);
|
||||
if (cfg_limit) {
|
||||
val = json_integer_value(cfg_limit);
|
||||
|
||||
if (!json_is_integer(cfg_limit) || val <= 0)
|
||||
error("Setting 'limit' must be a positive integer");
|
||||
|
||||
rtnl_netem_set_limit(ne, val);
|
||||
}
|
||||
else
|
||||
rtnl_netem_set_limit(ne, 0);
|
||||
|
||||
if (config_setting_lookup_int(cfg, "delay", &val)) {
|
||||
if (val <= 0)
|
||||
cerror(cfg, "Invalid value '%d' for delay setting", val);
|
||||
if (cfg_delay) {
|
||||
val = json_integer_value(cfg_delay);
|
||||
|
||||
if (!json_is_integer(cfg_delay) || val <= 0)
|
||||
error("Setting 'delay' must be a positive integer");
|
||||
|
||||
rtnl_netem_set_delay(ne, val);
|
||||
}
|
||||
|
||||
if (config_setting_lookup_int(cfg, "jitter", &val)) {
|
||||
if (val <= 0)
|
||||
cerror(cfg, "Invalid value '%d' for jitter setting", val);
|
||||
if (cfg_jitter) {
|
||||
val = json_integer_value(cfg_jitter);
|
||||
|
||||
if (!json_is_integer(cfg_jitter) || val <= 0)
|
||||
error("Setting 'jitter' must be a positive integer");
|
||||
|
||||
rtnl_netem_set_jitter(ne, val);
|
||||
}
|
||||
|
||||
if (config_setting_lookup_int(cfg, "loss", &val)) {
|
||||
if (val < 0 || val > 100)
|
||||
cerror(cfg, "Invalid percentage value '%d' for loss setting", val);
|
||||
if (cfg_loss) {
|
||||
val = json_integer_value(cfg_loss);
|
||||
|
||||
if (!json_is_integer(cfg_loss) || val < 0 || val > 100)
|
||||
error("Setting 'loss' must be a positive integer within the range [ 0, 100 ]");
|
||||
|
||||
rtnl_netem_set_loss(ne, val);
|
||||
}
|
||||
|
||||
if (config_setting_lookup_int(cfg, "duplicate", &val)) {
|
||||
if (val < 0 || val > 100)
|
||||
cerror(cfg, "Invalid percentage value '%d' for duplicate setting", val);
|
||||
if (cfg_duplicate) {
|
||||
val = json_integer_value(cfg_duplicate);
|
||||
|
||||
if (!json_is_integer(cfg_duplicate) || val < 0 || val > 100)
|
||||
error("Setting 'duplicate' must be a positive integer within the range [ 0, 100 ]");
|
||||
|
||||
rtnl_netem_set_duplicate(ne, val);
|
||||
}
|
||||
|
||||
if (config_setting_lookup_int(cfg, "corruption", &val)) {
|
||||
if (val < 0 || val > 100)
|
||||
cerror(cfg, "Invalid percentage value '%d' for corruption setting", val);
|
||||
if (cfg_corruption) {
|
||||
val = json_integer_value(cfg_corruption);
|
||||
|
||||
if (!json_is_integer(cfg_corruption) || val < 0 || val > 100)
|
||||
error("Setting 'corruption' must be a positive integer within the range [ 0, 100 ]");
|
||||
|
||||
rtnl_netem_set_corruption_probability(ne, val);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/** Logging routines that depend on libconfig.
|
||||
/** Logging routines that depend on jansson.
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
|
@ -28,35 +28,39 @@
|
|||
#include "log.h"
|
||||
#include "log_config.h"
|
||||
#include "utils.h"
|
||||
#include "string.h"
|
||||
|
||||
int log_parse(struct log *l, config_setting_t *cfg)
|
||||
int log_parse(struct log *l, json_t *cfg)
|
||||
{
|
||||
const char *fac, *pth;
|
||||
int lvl;
|
||||
const char *facilities = NULL;
|
||||
const char *path = NULL;
|
||||
int ret;
|
||||
|
||||
if (!config_setting_is_group(cfg))
|
||||
cerror(cfg, "Setting 'log' must be a group.");
|
||||
json_error_t err;
|
||||
|
||||
if (config_setting_lookup_int(cfg, "level", &lvl))
|
||||
l->level = lvl;
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: s, s?: s }",
|
||||
"level", &l->level,
|
||||
"file", &path,
|
||||
"facilities", &facilities
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse logging configuration");
|
||||
|
||||
if (config_setting_lookup_string(cfg, "file", &pth))
|
||||
l->path = pth;
|
||||
if (path)
|
||||
l->path = strdup(path);
|
||||
|
||||
if (config_setting_lookup_string(cfg, "facilities", &fac))
|
||||
log_set_facility_expression(l, fac);
|
||||
if (facilities)
|
||||
log_set_facility_expression(l, facilities);
|
||||
|
||||
l->state = STATE_PARSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cerror(config_setting_t *cfg, const char *fmt, ...)
|
||||
void jerror(json_error_t *err, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *buf = NULL;
|
||||
const char *file;
|
||||
int line;
|
||||
|
||||
struct log *l = global_log ? global_log : &default_log;
|
||||
|
||||
|
@ -64,12 +68,10 @@ void cerror(config_setting_t *cfg, const char *fmt, ...)
|
|||
vstrcatf(&buf, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
line = config_setting_source_line(cfg);
|
||||
file = config_setting_source_file(cfg);
|
||||
if (!file)
|
||||
file = config_setting_get_hook(config_root_setting(cfg->config));
|
||||
|
||||
log_print(l, LOG_LVL_ERROR, "%s in %s:%u", buf, file, line);
|
||||
log_print(l, LOG_LVL_ERROR, "%s:", buf);
|
||||
{ INDENT
|
||||
log_print(l, LOG_LVL_ERROR, "%s in %s:%d:%d", err->text, err->source, err->line, err->column);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
|
||||
|
|
|
@ -162,11 +162,11 @@ invalid_format:
|
|||
return -1;
|
||||
}
|
||||
|
||||
int mapping_entry_parse(struct mapping_entry *e, config_setting_t *cfg)
|
||||
int mapping_entry_parse(struct mapping_entry *e, json_t *cfg)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
str = config_setting_get_string(cfg);
|
||||
str = json_string_value(cfg);
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
|
@ -195,27 +195,23 @@ int mapping_destroy(struct mapping *m)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mapping_parse(struct mapping *m, config_setting_t *cfg)
|
||||
int mapping_parse(struct mapping *m, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(m->state == STATE_INITIALIZED);
|
||||
|
||||
if (!config_setting_is_array(cfg))
|
||||
if (!json_is_array(cfg))
|
||||
return -1;
|
||||
|
||||
m->real_length = 0;
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg); i++) {
|
||||
config_setting_t *cfg_mapping;
|
||||
|
||||
cfg_mapping = config_setting_get_elem(cfg, i);
|
||||
if (!cfg_mapping)
|
||||
return -1;
|
||||
|
||||
size_t index;
|
||||
json_t *cfg_entry;
|
||||
json_array_foreach(cfg, index, cfg_entry) {
|
||||
struct mapping_entry *e = alloc(sizeof(struct mapping_entry));
|
||||
|
||||
ret = mapping_entry_parse(e, cfg_mapping);
|
||||
ret = mapping_entry_parse(e, cfg_entry);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
116
lib/node.c
116
lib/node.c
|
@ -21,7 +21,6 @@
|
|||
*********************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "sample.h"
|
||||
#include "node.h"
|
||||
|
@ -52,28 +51,32 @@ int node_init(struct node *n, struct node_type *vt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int node_parse(struct node *n, config_setting_t *cfg)
|
||||
int node_parse(struct node *n, json_t *cfg, const char *name)
|
||||
{
|
||||
struct plugin *p;
|
||||
const char *type, *name;
|
||||
int ret;
|
||||
|
||||
name = config_setting_name(cfg);
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "type", &type))
|
||||
cerror(cfg, "Missing node type");
|
||||
const char *type;
|
||||
|
||||
n->name = strdup(name);
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: i }",
|
||||
"type", &type,
|
||||
"vectorize", &n->vectorize
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse node '%s'", node_name(n));
|
||||
|
||||
p = plugin_lookup(PLUGIN_TYPE_NODE, type);
|
||||
assert(&p->node == n->_vt);
|
||||
|
||||
config_setting_lookup_int(cfg, "vectorize", &n->vectorize);
|
||||
|
||||
n->name = strdup(name);
|
||||
|
||||
ret = n->_vt->parse ? n->_vt->parse(n, cfg) : 0;
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to parse node '%s'", node_name(n));
|
||||
error("Failed to parse node '%s'", node_name(n));
|
||||
|
||||
n->cfg = cfg;
|
||||
n->state = STATE_PARSED;
|
||||
|
||||
return ret;
|
||||
|
@ -85,10 +88,9 @@ int node_parse_cli(struct node *n, int argc, char *argv[])
|
|||
|
||||
assert(n->_vt);
|
||||
|
||||
n->vectorize = 1;
|
||||
n->name = "cli";
|
||||
|
||||
if (n->_vt->parse_cli) {
|
||||
n->name = strdup("cli");
|
||||
|
||||
ret = n->_vt->parse_cli(n, argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -96,21 +98,11 @@ int node_parse_cli(struct node *n, int argc, char *argv[])
|
|||
n->state = STATE_PARSED;
|
||||
}
|
||||
else {
|
||||
config_t cfg;
|
||||
config_setting_t *cfg_root;
|
||||
n->cfg = json_load_cli(argc, argv);
|
||||
if (!n->cfg)
|
||||
return -1;
|
||||
|
||||
config_init(&cfg);
|
||||
|
||||
ret = config_read_cli(&cfg, argc, argv);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
cfg_root = config_root_setting(&cfg);
|
||||
|
||||
ret = node_parse(n, cfg_root);
|
||||
|
||||
out:
|
||||
config_destroy(&cfg);
|
||||
ret = node_parse(n, n->cfg, "cli");
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -279,47 +271,57 @@ int node_reverse(struct node *n)
|
|||
return n->_vt->reverse ? n->_vt->reverse(n) : -1;
|
||||
}
|
||||
|
||||
int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all)
|
||||
int node_parse_list(struct list *list, json_t *cfg, struct list *all)
|
||||
{
|
||||
const char *str;
|
||||
struct node *node;
|
||||
const char *str;
|
||||
char *allstr = NULL;
|
||||
|
||||
switch (config_setting_type(cfg)) {
|
||||
case CONFIG_TYPE_STRING:
|
||||
str = config_setting_get_string(cfg);
|
||||
if (str) {
|
||||
node = list_lookup(all, str);
|
||||
if (node)
|
||||
list_push(list, node);
|
||||
else
|
||||
cerror(cfg, "Unknown outgoing node '%s'", str);
|
||||
}
|
||||
else
|
||||
cerror(cfg, "Invalid outgoing node");
|
||||
size_t index;
|
||||
json_t *elm;
|
||||
|
||||
switch (json_typeof(cfg)) {
|
||||
case JSON_STRING:
|
||||
str = json_string_value(cfg);
|
||||
node = list_lookup(all, str);
|
||||
if (!node)
|
||||
goto invalid2;
|
||||
|
||||
list_push(list, node);
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_ARRAY:
|
||||
for (int i = 0; i < config_setting_length(cfg); i++) {
|
||||
config_setting_t *elm = config_setting_get_elem(cfg, i);
|
||||
case JSON_ARRAY:
|
||||
json_array_foreach(cfg, index, elm) {
|
||||
if (!json_is_string(elm))
|
||||
goto invalid;
|
||||
|
||||
str = config_setting_get_string(elm);
|
||||
if (str) {
|
||||
node = list_lookup(all, str);
|
||||
if (!node)
|
||||
cerror(elm, "Unknown outgoing node '%s'", str);
|
||||
else if (node->_vt->write == NULL)
|
||||
cerror(cfg, "Output node '%s' is not supported as a sink.", node_name(node));
|
||||
node = list_lookup(all, json_string_value(elm));
|
||||
if (!node)
|
||||
|
||||
list_push(list, node);
|
||||
}
|
||||
else
|
||||
cerror(cfg, "Invalid outgoing node");
|
||||
|
||||
list_push(list, node);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
cerror(cfg, "Invalid output node(s)");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
invalid:
|
||||
error("The node list must be an a single or an array of strings referring to the keys of the 'nodes' section");
|
||||
|
||||
return -1;
|
||||
|
||||
invalid2:
|
||||
for (size_t i = 0; i < list_length(all); i++) {
|
||||
struct node *n = list_at(all, i);
|
||||
|
||||
strcatf(&allstr, " %s", node_name_short(n));
|
||||
}
|
||||
|
||||
error("Unknown node '%s'. Choose of one of: %s", str, allstr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -11,33 +11,43 @@
|
|||
|
||||
#include "nodes/cbuilder.h"
|
||||
|
||||
int cbuilder_parse(struct node *n, config_setting_t *cfg)
|
||||
int cbuilder_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct cbuilder *cb = n->_vd;
|
||||
config_setting_t *cfg_params;
|
||||
json_t *cfg_param, *cfg_params = NULL;
|
||||
|
||||
const char *model;
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "timestep", &cb->timestep))
|
||||
cerror(cfg, "CBuilder model requires 'timestep' setting");
|
||||
int ret;
|
||||
size_t index;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "model", &model))
|
||||
cerror(cfg, "CBuilder model requires 'model' setting");
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: f, s: s, s: b }",
|
||||
"timestep", &cb->timestep,
|
||||
"model", &model,
|
||||
"parameters", &cfg_params
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
cb->model = (struct cbuilder_model *) plugin_lookup(PLUGIN_TYPE_MODEL_CBUILDER, model);
|
||||
if (!cb->model)
|
||||
cerror(cfg, "Unknown model '%s'", model);
|
||||
error("Unknown model '%s' of node %s", model, node_name(n));
|
||||
|
||||
cfg_params = config_setting_get_member(cfg, "parameters");
|
||||
if (cfg_params) {
|
||||
if (!config_setting_is_array(cfg_params))
|
||||
cerror(cfg_params, "Model parameters must be an array of numbers!");
|
||||
if (!json_is_array(cfg_params))
|
||||
error("Setting 'parameters' of node %s must be an JSON array of numbers!", node_name(n));
|
||||
|
||||
cb->paramlen = config_setting_length(cfg_params);
|
||||
cb->paramlen = json_array_size(cfg_params);
|
||||
cb->params = alloc(cb->paramlen * sizeof(double));
|
||||
|
||||
for (int i = 0; i < cb->paramlen; i++)
|
||||
cb->params[i] = config_setting_get_float_elem(cfg_params, i);
|
||||
json_array_foreach(cfg_params, index, cfg_param) {
|
||||
if (json_is_number(cfg_param))
|
||||
error("Setting 'parameters' of node %s must be an JSON array of numbers!", node_name(n));
|
||||
|
||||
cb->params[index] = json_number_value(cfg_params);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
128
lib/nodes/file.c
128
lib/nodes/file.c
|
@ -64,15 +64,29 @@ static AFILE * file_reopen(struct file_direction *dir)
|
|||
return afopen(dir->uri, dir->mode);
|
||||
}
|
||||
|
||||
static int file_parse_direction(config_setting_t *cfg, struct file *f, int d)
|
||||
static int file_parse_direction(json_t *cfg, struct file *f, int d)
|
||||
{
|
||||
struct file_direction *dir = (d == FILE_READ) ? &f->read : &f->write;
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "uri", &dir->fmt))
|
||||
return -1;
|
||||
const char *format = NULL;
|
||||
const char *mode = NULL;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "mode", &dir->mode))
|
||||
dir->mode = (d == FILE_READ) ? "r" : "w+";
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: s }",
|
||||
"uri", &format,
|
||||
"mode", &mode
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to ");
|
||||
|
||||
if (format)
|
||||
dir->format = strdup(format);
|
||||
|
||||
if (mode)
|
||||
dir->mode = strdup(mode);
|
||||
else
|
||||
dir->mode = strdup(d == FILE_READ ? "r" : "w+");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -104,30 +118,61 @@ static struct timespec file_calc_read_offset(const struct timespec *first, const
|
|||
}
|
||||
}
|
||||
|
||||
int file_parse(struct node *n, config_setting_t *cfg)
|
||||
int file_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct file *f = n->_vd;
|
||||
|
||||
config_setting_t *cfg_in, *cfg_out;
|
||||
json_t *cfg_in = NULL;
|
||||
json_t *cfg_out = NULL;
|
||||
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o }",
|
||||
"in", &cfg_in,
|
||||
"out", &cfg_out
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
cfg_out = config_setting_get_member(cfg, "out");
|
||||
if (cfg_out) {
|
||||
if (file_parse_direction(cfg_out, f, FILE_WRITE))
|
||||
cerror(cfg_out, "Failed to parse output file for node %s", node_name(n));
|
||||
error("Failed to parse output file for node %s", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_bool(cfg_out, "flush", &f->flush))
|
||||
f->flush = 0;
|
||||
f->flush = 0;
|
||||
|
||||
ret = json_unpack_ex(cfg_out, &err, 0, "{ s?: b }", "flush", &f->flush);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
}
|
||||
|
||||
cfg_in = config_setting_get_member(cfg, "in");
|
||||
if (cfg_in) {
|
||||
const char *eof;
|
||||
const char *eof = NULL;
|
||||
const char *epoch_mode = NULL;
|
||||
double epoch_flt = 0;
|
||||
|
||||
/* Default values */
|
||||
f->read_rate = 0;
|
||||
f->read_eof = FILE_EOF_EXIT;
|
||||
f->read_epoch_mode = FILE_EPOCH_DIRECT;
|
||||
|
||||
if (file_parse_direction(cfg_in, f, FILE_READ))
|
||||
cerror(cfg_in, "Failed to parse input file for node %s", node_name(n));
|
||||
error("Failed to parse input file for node %s", node_name(n));
|
||||
|
||||
ret = json_unpack_ex(cfg_in, &err, 0, "{ s?: s, s?: f, s?: s, s?: f }",
|
||||
"eof", &eof,
|
||||
"rate", &f->read_rate,
|
||||
"epoch_mode", &epoch_mode,
|
||||
"epoch", &epoch_flt
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
f->read_epoch = time_from_double(epoch_flt);
|
||||
|
||||
/* More read specific settings */
|
||||
if (config_setting_lookup_string(cfg_in, "eof", &eof)) {
|
||||
if (eof) {
|
||||
if (!strcmp(eof, "exit"))
|
||||
f->read_eof = FILE_EOF_EXIT;
|
||||
else if (!strcmp(eof, "rewind"))
|
||||
|
@ -135,22 +180,10 @@ int file_parse(struct node *n, config_setting_t *cfg)
|
|||
else if (!strcmp(eof, "wait"))
|
||||
f->read_eof = FILE_EOF_WAIT;
|
||||
else
|
||||
cerror(cfg_in, "Invalid mode '%s' for 'eof' setting", eof);
|
||||
error("Invalid mode '%s' for 'eof' setting of node %s", eof, node_name(n));
|
||||
}
|
||||
else
|
||||
f->read_eof = FILE_EOF_EXIT;
|
||||
|
||||
if (!config_setting_lookup_float(cfg_in, "rate", &f->read_rate))
|
||||
f->read_rate = 0; /* Disable fixed rate sending. Using timestamps of file instead */
|
||||
|
||||
double epoch_flt;
|
||||
if (!config_setting_lookup_float(cfg_in, "epoch", &epoch_flt))
|
||||
epoch_flt = 0;
|
||||
|
||||
f->read_epoch = time_from_double(epoch_flt);
|
||||
|
||||
const char *epoch_mode;
|
||||
if (config_setting_lookup_string(cfg_in, "epoch_mode", &epoch_mode)) {
|
||||
if (epoch_mode) {
|
||||
if (!strcmp(epoch_mode, "direct"))
|
||||
f->read_epoch_mode = FILE_EPOCH_DIRECT;
|
||||
else if (!strcmp(epoch_mode, "wait"))
|
||||
|
@ -162,10 +195,8 @@ int file_parse(struct node *n, config_setting_t *cfg)
|
|||
else if (!strcmp(epoch_mode, "original"))
|
||||
f->read_epoch_mode = FILE_EPOCH_ORIGINAL;
|
||||
else
|
||||
cerror(cfg_in, "Invalid value '%s' for setting 'epoch_mode'", epoch_mode);
|
||||
error("Invalid value '%s' for setting 'epoch_mode' of node %s", epoch_mode, node_name(n));
|
||||
}
|
||||
else
|
||||
f->read_epoch_mode = FILE_EPOCH_DIRECT;
|
||||
}
|
||||
|
||||
n->_vd = f;
|
||||
|
@ -178,7 +209,7 @@ char * file_print(struct node *n)
|
|||
struct file *f = n->_vd;
|
||||
char *buf = NULL;
|
||||
|
||||
if (f->read.fmt) {
|
||||
if (f->read.format) {
|
||||
const char *epoch_str = NULL;
|
||||
switch (f->read_epoch_mode) {
|
||||
case FILE_EPOCH_DIRECT: epoch_str = "direct"; break;
|
||||
|
@ -196,7 +227,7 @@ char * file_print(struct node *n)
|
|||
}
|
||||
|
||||
strcatf(&buf, "in=%s, mode=%s, eof=%s, epoch_mode=%s, epoch=%.2f",
|
||||
f->read.uri ? f->read.uri : f->read.fmt,
|
||||
f->read.uri ? f->read.uri : f->read.format,
|
||||
f->read.mode,
|
||||
eof_str,
|
||||
epoch_str,
|
||||
|
@ -207,9 +238,9 @@ char * file_print(struct node *n)
|
|||
strcatf(&buf, ", rate=%.1f", f->read_rate);
|
||||
}
|
||||
|
||||
if (f->write.fmt) {
|
||||
if (f->write.format) {
|
||||
strcatf(&buf, ", out=%s, mode=%s",
|
||||
f->write.uri ? f->write.uri : f->write.fmt,
|
||||
f->write.uri ? f->write.uri : f->write.format,
|
||||
f->write.mode
|
||||
);
|
||||
}
|
||||
|
@ -241,9 +272,9 @@ int file_start(struct node *n)
|
|||
struct timespec now = time_now();
|
||||
int ret;
|
||||
|
||||
if (f->read.fmt) {
|
||||
if (f->read.format) {
|
||||
/* Prepare file name */
|
||||
f->read.uri = file_format_name(f->read.fmt, &now);
|
||||
f->read.uri = file_format_name(f->read.format, &now);
|
||||
|
||||
/* Open file */
|
||||
f->read.handle = file_reopen(&f->read);
|
||||
|
@ -262,9 +293,10 @@ int file_start(struct node *n)
|
|||
/* Get timestamp of first line */
|
||||
if (f->read_epoch_mode != FILE_EPOCH_ORIGINAL) {
|
||||
struct sample s;
|
||||
struct sample *smps[] = { &s };
|
||||
s.capacity = 0;
|
||||
|
||||
ret = io_format_villas_fscan(f->read.handle->file, &s, NULL);
|
||||
ret = io_format_villas_fscan(f->read.handle->file, smps, 1, NULL);
|
||||
if (ret < 0)
|
||||
error("Failed to read first timestamp of node %s", node_name(n));
|
||||
|
||||
|
@ -274,9 +306,9 @@ int file_start(struct node *n)
|
|||
}
|
||||
}
|
||||
|
||||
if (f->write.fmt) {
|
||||
if (f->write.format) {
|
||||
/* Prepare file name */
|
||||
f->write.uri = file_format_name(f->write.fmt, &now);
|
||||
f->write.uri = file_format_name(f->write.format, &now);
|
||||
|
||||
/* Open file */
|
||||
f->write.handle = file_reopen(&f->write);
|
||||
|
@ -307,15 +339,14 @@ int file_stop(struct node *n)
|
|||
int file_read(struct node *n, struct sample *smps[], unsigned cnt)
|
||||
{
|
||||
struct file *f = n->_vd;
|
||||
struct sample *s = smps[0];
|
||||
int values, flags;
|
||||
uint64_t ex;
|
||||
|
||||
assert(f->read.handle);
|
||||
assert(cnt == 1);
|
||||
|
||||
retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get message and timestamp */
|
||||
if (values < 0) {
|
||||
retry: values = io_format_villas_fscan(f->read.handle->file, smps, 1, &flags); /* Get message and timestamp */
|
||||
if (values <= 0) {
|
||||
if (afeof(f->read.handle)) {
|
||||
switch (f->read_eof) {
|
||||
case FILE_EOF_REWIND:
|
||||
|
@ -345,14 +376,14 @@ retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get
|
|||
|
||||
if (f->read_epoch_mode != FILE_EPOCH_ORIGINAL) {
|
||||
if (!f->read_rate || aftell(f->read.handle) == 0) {
|
||||
s->ts.origin = time_add(&s->ts.origin, &f->read_offset);
|
||||
smps[0]->ts.origin = time_add(&smps[0]->ts.origin, &f->read_offset);
|
||||
|
||||
ex = timerfd_wait_until(f->read_timer, &s->ts.origin);
|
||||
ex = timerfd_wait_until(f->read_timer, &smps[0]->ts.origin);
|
||||
}
|
||||
else { /* Wait with fixed rate delay */
|
||||
ex = timerfd_wait(f->read_timer);
|
||||
|
||||
s->ts.origin = time_now();
|
||||
smps[0]->ts.origin = time_now();
|
||||
}
|
||||
|
||||
/* Check for overruns */
|
||||
|
@ -368,12 +399,11 @@ retry: values = io_format_villas_fscan(f->read.handle->file, s, &flags); /* Get
|
|||
int file_write(struct node *n, struct sample *smps[], unsigned cnt)
|
||||
{
|
||||
struct file *f = n->_vd;
|
||||
struct sample *s = smps[0];
|
||||
|
||||
assert(f->write.handle);
|
||||
assert(cnt == 1);
|
||||
|
||||
io_format_villas_fprint(f->write.handle->file, s, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET);
|
||||
io_format_villas_fprint(f->write.handle->file, smps, cnt, IO_FORMAT_ALL & ~IO_FORMAT_OFFSET);
|
||||
|
||||
if (f->flush)
|
||||
afflush(f->write.handle);
|
||||
|
|
|
@ -34,7 +34,6 @@ void fpga_dump(struct fpga *f)
|
|||
int fpga_init(struct super_node *sn)
|
||||
{
|
||||
int ret;
|
||||
config_setting_t *cfg, *cfg_fpgas;
|
||||
|
||||
ret = pci_init(&pci);
|
||||
if (ret)
|
||||
|
@ -44,6 +43,9 @@ int fpga_init(struct super_node *sn)
|
|||
if (ret)
|
||||
error("Failed to initiliaze VFIO sub-system");
|
||||
|
||||
#if 0
|
||||
json_t *cfg, *cfg_fpgas;
|
||||
|
||||
/* Parse FPGA configuration */
|
||||
cfg = config_root_setting(&sn->cfg);
|
||||
cfg_fpgas = config_setting_lookup(cfg, "fpgas");
|
||||
|
@ -53,7 +55,7 @@ int fpga_init(struct super_node *sn)
|
|||
ret = fpga_card_parse_list(&cards, cfg_fpgas);
|
||||
if (ret)
|
||||
cerror(cfg, "Failed to parse VILLASfpga config");
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -76,7 +78,7 @@ int fpga_deinit()
|
|||
return 0;
|
||||
}
|
||||
|
||||
int fpga_parse(struct node *n, config_setting_t *cfg)
|
||||
int fpga_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct fpga *f = n->_vd;
|
||||
struct fpga_card *card;
|
||||
|
@ -85,11 +87,18 @@ int fpga_parse(struct node *n, config_setting_t *cfg)
|
|||
char *cpy, *card_name, *ip_name;
|
||||
const char *dm;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "datamover", &dm))
|
||||
cerror(cfg, "Node '%s' is missing the 'datamover' setting", node_name(n));
|
||||
json_error_t err;
|
||||
int ret;
|
||||
|
||||
if (!config_setting_lookup_bool(cfg, "use_irqs", &f->use_irqs))
|
||||
f->use_irqs = false;
|
||||
/* Default values */
|
||||
f->use_irqs = false;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: b }",
|
||||
"datamover", &dm,
|
||||
"use_irqs", &f->use_irqs
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
cpy = strdup(dm); /* strtok can not operate on type const char * */
|
||||
|
||||
|
@ -98,13 +107,13 @@ int fpga_parse(struct node *n, config_setting_t *cfg)
|
|||
|
||||
card = list_lookup(&cards, card_name);
|
||||
if (!card)
|
||||
cerror(cfg, "There is no FPGA card named '%s", card_name);
|
||||
error("There is no FPGA card named '%s' used by node %s", card_name, node_name(n));
|
||||
|
||||
ip = list_lookup(&card->ips, ip_name);
|
||||
if (!ip)
|
||||
cerror(cfg, "There is no datamover named '%s' on the FPGA card '%s'", ip_name, card_name);
|
||||
error("There is no datamover named '%s' on the FPGA card '%s' used by node %s", ip_name, card_name, node_name(n));
|
||||
if (ip->_vt->type != FPGA_IP_TYPE_DM_DMA && ip->_vt->type != FPGA_IP_TYPE_DM_FIFO)
|
||||
cerror(cfg, "The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name);
|
||||
error("The IP '%s' on FPGA card '%s' is not a datamover", ip_name, card_name);
|
||||
|
||||
free(cpy);
|
||||
|
||||
|
|
|
@ -27,15 +27,23 @@
|
|||
#include "nodes/loopback.h"
|
||||
#include "memory.h"
|
||||
|
||||
int loopback_parse(struct node *n, config_setting_t *cfg)
|
||||
int loopback_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct loopback *l = n->_vd;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "queuelen", &l->queuelen))
|
||||
l->queuelen = DEFAULT_QUEUELEN;
|
||||
json_error_t err;
|
||||
int ret;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "samplelen", &l->samplelen))
|
||||
l->samplelen = DEFAULT_SAMPLELEN;
|
||||
/* Default values */
|
||||
l->queuelen = DEFAULT_QUEUELEN;
|
||||
l->samplelen = DEFAULT_SAMPLELEN;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: i, s?: i }",
|
||||
"queuelen", &l->queuelen,
|
||||
"samplelen", &l->samplelen
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -46,25 +46,28 @@ int nanomsg_reverse(struct node *n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg)
|
||||
static int nanomsg_parse_endpoints(struct list *l, json_t *cfg)
|
||||
{
|
||||
const char *ep;
|
||||
|
||||
switch (config_setting_type(cfg)) {
|
||||
case CONFIG_TYPE_LIST:
|
||||
case CONFIG_TYPE_ARRAY:
|
||||
for (int j = 0; j < config_setting_length(cfg); j++) {
|
||||
const char *ep = config_setting_get_string_elem(cfg, j);
|
||||
size_t index;
|
||||
json_t *cfg_val;
|
||||
|
||||
switch (json_typeof(cfg)) {
|
||||
case JSON_ARRAY:
|
||||
json_array_foreach(cfg, index, cfg_val) {
|
||||
ep = json_string_value(cfg_val);
|
||||
if (!ep)
|
||||
return -1;
|
||||
|
||||
list_push(l, strdup(ep));
|
||||
}
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
ep = config_setting_get_string(cfg);
|
||||
case JSON_STRING:
|
||||
ep = json_string_value(cfg);
|
||||
|
||||
list_push(l, strdup(ep));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -74,28 +77,36 @@ static int nanomsg_parse_endpoints(struct list *l, config_setting_t *cfg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int nanomsg_parse(struct node *n, config_setting_t *cfg)
|
||||
int nanomsg_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
struct nanomsg *m = n->_vd;
|
||||
|
||||
config_setting_t *cfg_pub, *cfg_sub;
|
||||
json_error_t err;
|
||||
|
||||
json_t *cfg_pub = NULL;
|
||||
json_t *cfg_sub = NULL;
|
||||
|
||||
list_init(&m->publisher.endpoints);
|
||||
list_init(&m->subscriber.endpoints);
|
||||
|
||||
cfg_pub = config_setting_lookup(cfg, "publish");
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o }",
|
||||
"publish", &cfg_pub,
|
||||
"subscribe", &cfg_sub
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
if (cfg_pub) {
|
||||
ret = nanomsg_parse_endpoints(&m->publisher.endpoints, cfg_pub);
|
||||
if (ret < 0)
|
||||
cerror(cfg_pub, "Invalid type for 'publish' setting of node %s", node_name(n));
|
||||
error("Invalid type for 'publish' setting of node %s", node_name(n));
|
||||
}
|
||||
|
||||
cfg_sub = config_setting_lookup(cfg, "subscribe");
|
||||
if (cfg_sub) {
|
||||
ret = nanomsg_parse_endpoints(&m->subscriber.endpoints, cfg_sub);
|
||||
if (ret < 0)
|
||||
cerror(cfg_pub, "Invalid type for 'subscribe' setting of node %s", node_name(n));
|
||||
error("Invalid type for 'subscribe' setting of node %s", node_name(n));
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -197,26 +197,31 @@ static int ngsi_parse_entity(json_t *entity, struct ngsi *i, struct sample *smps
|
|||
return cnt;
|
||||
}
|
||||
|
||||
static int ngsi_parse_mapping(struct list *mapping, config_setting_t *cfg)
|
||||
static int ngsi_parse_mapping(struct list *mapping, json_t *cfg)
|
||||
{
|
||||
if (!config_setting_is_array(cfg))
|
||||
if (!json_is_array(cfg))
|
||||
return -1;
|
||||
|
||||
list_init(mapping);
|
||||
|
||||
for (int j = 0; j < config_setting_length(cfg); j++) {
|
||||
const char *token = config_setting_get_string_elem(cfg, j);
|
||||
size_t index;
|
||||
json_t *cfg_token;
|
||||
|
||||
json_array_foreach(cfg, index, cfg_token) {
|
||||
const char *token;
|
||||
|
||||
token = json_string_value(cfg_token);
|
||||
if (!token)
|
||||
return -2;
|
||||
|
||||
struct ngsi_attribute *a = alloc(sizeof(struct ngsi_attribute));
|
||||
|
||||
a->index = j;
|
||||
a->index = index;
|
||||
|
||||
/* Parse Attribute: AttributeName(AttributeType) */
|
||||
int bytes;
|
||||
if (sscanf(token, "%m[^(](%m[^)])%n", &a->name, &a->type, &bytes) != 2)
|
||||
cerror(cfg, "Invalid mapping token: '%s'", token);
|
||||
error("Invalid mapping token: '%s'", token);
|
||||
|
||||
token += bytes;
|
||||
|
||||
|
@ -241,7 +246,7 @@ static int ngsi_parse_mapping(struct list *mapping, config_setting_t *cfg)
|
|||
.name = "index",
|
||||
.type = "integer"
|
||||
};
|
||||
assert(asprintf(&i.value, "%u", j));
|
||||
assert(asprintf(&i.value, "%zu", index));
|
||||
|
||||
list_push(&a->metadata, memdup(&s, sizeof(s)));
|
||||
list_push(&a->metadata, memdup(&i, sizeof(i)));
|
||||
|
@ -387,18 +392,6 @@ out: json_decref(request);
|
|||
|
||||
int ngsi_init(struct super_node *sn)
|
||||
{
|
||||
config_setting_t *cfg;
|
||||
|
||||
cfg = config_root_setting(&sn->cfg);
|
||||
|
||||
const char *tname;
|
||||
if (config_setting_lookup_string(cfg, "name", &tname))
|
||||
name = strdup(tname);
|
||||
else {
|
||||
name = alloc(128); /** @todo missing free */
|
||||
gethostname((char *) name, 128);
|
||||
}
|
||||
|
||||
return curl_global_init(CURL_GLOBAL_ALL);
|
||||
}
|
||||
|
||||
|
@ -411,37 +404,36 @@ int ngsi_deinit()
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ngsi_parse(struct node *n, config_setting_t *cfg)
|
||||
int ngsi_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct ngsi *i = n->_vd;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "access_token", &i->access_token))
|
||||
i->access_token = NULL; /* disabled by default */
|
||||
int ret;
|
||||
json_error_t err;
|
||||
json_t *cfg_mapping;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "endpoint", &i->endpoint))
|
||||
cerror(cfg, "Missing NGSI endpoint for node %s", node_name(n));
|
||||
/* Default values */
|
||||
i->access_token = NULL; /* disabled by default */
|
||||
i->ssl_verify = 1; /* verify by default */
|
||||
i->timeout = 1; /* default value */
|
||||
i->rate = 5; /* default value */
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "entity_id", &i->entity_id))
|
||||
cerror(cfg, "Missing NGSI entity ID for node %s", node_name(n));
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s: s, s: s, s: s, s?: b, s?: f, s?: f }",
|
||||
"access_token", &i->access_token,
|
||||
"endpoint", &i->endpoint,
|
||||
"entity_id", &i->entity_id,
|
||||
"entity_type", &i->entity_type,
|
||||
"ssl_verify", &i->ssl_verify,
|
||||
"timeout", &i->timeout,
|
||||
"rate", &i->rate,
|
||||
"mapping", &cfg_mapping
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "entity_type", &i->entity_type))
|
||||
cerror(cfg, "Missing NGSI entity type for node %s", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_bool(cfg, "ssl_verify", &i->ssl_verify))
|
||||
i->ssl_verify = 1; /* verify by default */
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "timeout", &i->timeout))
|
||||
i->timeout = 1; /* default value */
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "rate", &i->rate))
|
||||
i->rate = 5; /* default value */
|
||||
|
||||
config_setting_t *cfg_mapping = config_setting_get_member(cfg, "mapping");
|
||||
if (!cfg_mapping)
|
||||
cerror(cfg, "Missing mapping for node %s", node_name(n));
|
||||
|
||||
if (ngsi_parse_mapping(&i->mapping, cfg_mapping))
|
||||
cerror(cfg_mapping, "Invalid mapping for node %s", node_name(n));
|
||||
ret = ngsi_parse_mapping(&i->mapping, cfg_mapping);
|
||||
if (ret)
|
||||
error("Invalid setting 'mapping' of node %s", node_name(n));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -144,13 +144,20 @@ int opal_print_global()
|
|||
return 0;
|
||||
}
|
||||
|
||||
int opal_parse(struct node *n, config_setting_t *cfg)
|
||||
int opal_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct opal *o = n->_vd;
|
||||
|
||||
config_setting_lookup_int(cfg, "send_id", &o->send_id);
|
||||
config_setting_lookup_int(cfg, "recv_id", &o->recv_id);
|
||||
config_setting_lookup_bool(cfg, "reply", &o->reply);
|
||||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: i, s: i, s: b }",
|
||||
"send_id", &o->send_id,
|
||||
"recv_id", &o->recv_id,
|
||||
"reply", &o->reply
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,44 +36,49 @@
|
|||
#include "timing.h"
|
||||
#include "utils.h"
|
||||
|
||||
int shmem_parse(struct node *n, config_setting_t *cfg)
|
||||
int shmem_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct shmem *shm = n->_vd;
|
||||
const char *val;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "out_name", &shm->out_name))
|
||||
cerror(cfg, "Missing shared memory output queue name");
|
||||
int ret;
|
||||
json_t *cfg_exec = NULL;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "in_name", &shm->in_name))
|
||||
cerror(cfg, "Missing shared memory input queue name");
|
||||
/* Default values */
|
||||
shm->conf.queuelen = MAX(DEFAULT_SHMEM_QUEUELEN, n->vectorize);
|
||||
shm->conf.samplelen = DEFAULT_SHMEM_SAMPLELEN;
|
||||
shm->conf.polling = false;
|
||||
shm->exec = NULL;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "queuelen", &shm->conf.queuelen))
|
||||
shm->conf.queuelen = MAX(DEFAULT_SHMEM_QUEUELEN, n->vectorize);
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s: s, s?: i, s?: i, s?: b, s?: o }",
|
||||
"out_name", &shm->out_name,
|
||||
"in_name", &shm->in_name,
|
||||
"queuelen", &shm->conf.queuelen,
|
||||
"samplelen", &shm->conf.samplelen,
|
||||
"polling", &shm->conf.polling,
|
||||
"exec", &cfg_exec
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "samplelen", &shm->conf.samplelen))
|
||||
shm->conf.samplelen = DEFAULT_SHMEM_SAMPLELEN;
|
||||
if (cfg_exec) {
|
||||
if (!json_is_array(cfg_exec))
|
||||
error("Setting 'exec' of node %s must be a JSON array of strings", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_bool(cfg, "polling", &shm->conf.polling))
|
||||
shm->conf.polling = false;
|
||||
shm->exec = alloc(sizeof(char *) * (json_array_size(cfg_exec) + 1));
|
||||
|
||||
config_setting_t *exec_cfg = config_setting_lookup(cfg, "exec");
|
||||
if (!exec_cfg)
|
||||
shm->exec = NULL;
|
||||
else {
|
||||
if (!config_setting_is_array(exec_cfg))
|
||||
cerror(exec_cfg, "Invalid format for exec");
|
||||
size_t index;
|
||||
json_t *cfg_val;
|
||||
json_array_foreach(cfg_exec, index, cfg_val) {
|
||||
val = json_string_value(cfg_exec);
|
||||
if (!val)
|
||||
error("Setting 'exec' of node %s must be a JSON array of strings", node_name(n));
|
||||
|
||||
shm->exec = alloc(sizeof(char *) * (config_setting_length(exec_cfg) + 1));
|
||||
|
||||
int i;
|
||||
for (i = 0; i < config_setting_length(exec_cfg); i++) {
|
||||
const char *elm = config_setting_get_string_elem(exec_cfg, i);
|
||||
if (!elm)
|
||||
cerror(exec_cfg, "Invalid format for exec");
|
||||
|
||||
shm->exec[i] = strdup(elm);
|
||||
shm->exec[index] = strdup(val);
|
||||
}
|
||||
|
||||
shm->exec[i] = NULL;
|
||||
shm->exec[index] = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -45,43 +45,46 @@ enum signal_type signal_lookup_type(const char *type)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int signal_parse(struct node *n, config_setting_t *cfg)
|
||||
int signal_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct signal *s = n->_vd;
|
||||
|
||||
int ret;
|
||||
const char *type;
|
||||
const char *type = NULL;
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "signal", &type))
|
||||
s->type = SIGNAL_TYPE_MIXED;
|
||||
else {
|
||||
json_error_t err;
|
||||
|
||||
s->rt = 1;
|
||||
s->limit = -1;
|
||||
s->values = 1;
|
||||
s->rate = 10;
|
||||
s->frequency = 1;
|
||||
s->amplitude = 1;
|
||||
s->stddev = 0.02;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: b, s?: i, s?: i, s?: f, s?: f, s?: f, s?: f }",
|
||||
"signal", &type,
|
||||
"realtime", &s->rt,
|
||||
"limit", &s->limit,
|
||||
"values", &s->values,
|
||||
"rate", &s->rate,
|
||||
"frequency", &s->frequency,
|
||||
"amplitude", &s->amplitude,
|
||||
"stddev", &s->stddev
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
|
||||
if (type) {
|
||||
ret = signal_lookup_type(type);
|
||||
if (ret == -1)
|
||||
cerror(cfg, "Unknown signal type '%s'", type);
|
||||
error("Unknown signal type '%s' of node %s", type, node_name(n));
|
||||
|
||||
s->type = ret;
|
||||
}
|
||||
|
||||
if (!config_setting_lookup_bool(cfg, "realtime", &s->rt))
|
||||
s->rt = 1;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "limit", &s->limit))
|
||||
s->limit = -1;
|
||||
|
||||
if (!config_setting_lookup_int(cfg, "values", &s->values))
|
||||
s->values = 1;
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "rate", &s->rate))
|
||||
s->rate = 10;
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "frequency", &s->frequency))
|
||||
s->frequency = 1;
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "amplitude", &s->amplitude))
|
||||
s->amplitude = 1;
|
||||
|
||||
if (!config_setting_lookup_float(cfg, "stddev", &s->stddev))
|
||||
s->stddev = 0.02;
|
||||
else
|
||||
s->type = SIGNAL_TYPE_MIXED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -226,7 +229,7 @@ int signal_read(struct node *n, struct sample *smps[], unsigned cnt)
|
|||
}
|
||||
|
||||
if (s->limit > 0 && s->counter >= s->limit) {
|
||||
info("Reached limit");
|
||||
info("Reached limit of node %s", node_name(n));
|
||||
killme(SIGTERM);
|
||||
pause();
|
||||
}
|
||||
|
|
|
@ -561,18 +561,40 @@ int socket_write(struct node *n, struct sample *smps[], unsigned cnt)
|
|||
return -1;
|
||||
}
|
||||
|
||||
int socket_parse(struct node *n, config_setting_t *cfg)
|
||||
int socket_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
config_setting_t *cfg_multicast;
|
||||
const char *local, *remote, *layer, *hdr, *endian;
|
||||
int ret;
|
||||
|
||||
struct socket *s = n->_vd;
|
||||
|
||||
const char *local, *remote;
|
||||
const char *endian = NULL;
|
||||
const char *layer = NULL;
|
||||
const char *header = NULL;
|
||||
|
||||
int ret;
|
||||
|
||||
json_t *cfg_multicast = NULL;
|
||||
json_error_t err;
|
||||
|
||||
/* Default values */
|
||||
s->layer = SOCKET_LAYER_UDP;
|
||||
s->header = SOCKET_HEADER_DEFAULT;
|
||||
s->endian = SOCKET_ENDIAN_BIG;
|
||||
s->verify_source = 0;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s: s, s: s, s?: b, s?: o }",
|
||||
"layer", &layer,
|
||||
"header", &header,
|
||||
"endian", &endian,
|
||||
"remote", &remote,
|
||||
"local", &local,
|
||||
"verify_source", &s->verify_source,
|
||||
"multicast", &cfg_multicast
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
/* IP layer */
|
||||
if (!config_setting_lookup_string(cfg, "layer", &layer))
|
||||
s->layer = SOCKET_LAYER_UDP;
|
||||
else {
|
||||
if (layer) {
|
||||
if (!strcmp(layer, "ip"))
|
||||
s->layer = SOCKET_LAYER_IP;
|
||||
#ifdef __linux__
|
||||
|
@ -582,103 +604,89 @@ int socket_parse(struct node *n, config_setting_t *cfg)
|
|||
else if (!strcmp(layer, "udp"))
|
||||
s->layer = SOCKET_LAYER_UDP;
|
||||
else
|
||||
cerror(cfg, "Invalid layer '%s' for node %s", layer, node_name(n));
|
||||
error("Invalid layer '%s' for node %s", layer, node_name(n));
|
||||
}
|
||||
|
||||
/* Application header */
|
||||
if (!config_setting_lookup_string(cfg, "header", &hdr))
|
||||
s->header = SOCKET_HEADER_DEFAULT;
|
||||
else {
|
||||
if (!strcmp(hdr, "gtnet-skt") || (!strcmp(hdr, "none")))
|
||||
if (header) {
|
||||
if (!strcmp(header, "gtnet-skt") || (!strcmp(header, "none")))
|
||||
s->header = SOCKET_HEADER_NONE;
|
||||
else if (!strcmp(hdr, "gtnet-skt:fake") || (!strcmp(hdr, "fake")))
|
||||
else if (!strcmp(header, "gtnet-skt:fake") || (!strcmp(header, "fake")))
|
||||
s->header = SOCKET_HEADER_FAKE;
|
||||
else if (!strcmp(hdr, "villas") || !strcmp(hdr, "default"))
|
||||
else if (!strcmp(header, "villas") || !strcmp(header, "default"))
|
||||
s->header = SOCKET_HEADER_DEFAULT;
|
||||
else
|
||||
cerror(cfg, "Invalid application header type '%s' for node %s", hdr, node_name(n));
|
||||
error("Invalid application header type '%s' for node %s", header, node_name(n));
|
||||
}
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "endian", &endian))
|
||||
s->endian = SOCKET_ENDIAN_BIG;
|
||||
else {
|
||||
if (endian) {
|
||||
if (!strcmp(endian, "big") || !strcmp(endian, "network"))
|
||||
s->endian = SOCKET_ENDIAN_BIG;
|
||||
else if (!strcmp(endian, "little"))
|
||||
s->endian = SOCKET_ENDIAN_LITTLE;
|
||||
else
|
||||
cerror(cfg, "Invalid endianness type '%s' for node %s", endian, node_name(n));
|
||||
error("Invalid endianness type '%s' for node %s", endian, node_name(n));
|
||||
}
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "remote", &remote))
|
||||
cerror(cfg, "Missing remote address for node %s", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_string(cfg, "local", &local))
|
||||
cerror(cfg, "Missing local address for node %s", node_name(n));
|
||||
|
||||
if (!config_setting_lookup_bool(cfg, "verify_source", &s->verify_source))
|
||||
s->verify_source = 0;
|
||||
|
||||
ret = socket_parse_addr(local, (struct sockaddr *) &s->local, s->layer, AI_PASSIVE);
|
||||
if (ret) {
|
||||
cerror(cfg, "Failed to resolve local address '%s' of node %s: %s",
|
||||
error("Failed to resolve local address '%s' of node %s: %s",
|
||||
local, node_name(n), gai_strerror(ret));
|
||||
}
|
||||
|
||||
ret = socket_parse_addr(remote, (struct sockaddr *) &s->remote, s->layer, 0);
|
||||
if (ret) {
|
||||
cerror(cfg, "Failed to resolve remote address '%s' of node %s: %s",
|
||||
error("Failed to resolve remote address '%s' of node %s: %s",
|
||||
remote, node_name(n), gai_strerror(ret));
|
||||
}
|
||||
|
||||
cfg_multicast = config_setting_get_member(cfg, "multicast");
|
||||
if (cfg_multicast) {
|
||||
const char *group, *interface;
|
||||
const char *group, *interface = NULL;
|
||||
|
||||
if (!config_setting_lookup_bool(cfg_multicast, "enabled", &s->multicast.enabled))
|
||||
s->multicast.enabled = true;
|
||||
/* Default values */
|
||||
s->multicast.enabled = true;
|
||||
s->multicast.mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
s->multicast.loop = 0;
|
||||
s->multicast.ttl = 255;
|
||||
|
||||
if (!config_setting_lookup_string(cfg_multicast, "group", &group))
|
||||
cerror(cfg_multicast, "The multicast group requires a 'group' setting.");
|
||||
else {
|
||||
ret = inet_aton(group, &s->multicast.mreq.imr_multiaddr);
|
||||
if (!ret) {
|
||||
cerror(cfg_multicast, "Failed to resolve multicast group address '%s' of node %s",
|
||||
group, node_name(n));
|
||||
}
|
||||
ret = json_unpack_ex(cfg_multicast, &err, 0, "{ s?: b, s: s, s?: s, s?: b, s?: i }",
|
||||
"enabled", &s->multicast.enabled,
|
||||
"group", &group,
|
||||
"interface", &interface,
|
||||
"loop", &s->multicast.loop,
|
||||
"ttl", &s->multicast.ttl
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse setting 'multicast' of node %s", node_name(n));
|
||||
|
||||
ret = inet_aton(group, &s->multicast.mreq.imr_multiaddr);
|
||||
if (!ret) {
|
||||
error("Failed to resolve multicast group address '%s' of node %s",
|
||||
group, node_name(n));
|
||||
}
|
||||
|
||||
if (!config_setting_lookup_string(cfg_multicast, "interface", &interface))
|
||||
s->multicast.mreq.imr_interface.s_addr = INADDR_ANY;
|
||||
else {
|
||||
if (interface) {
|
||||
ret = inet_aton(group, &s->multicast.mreq.imr_interface);
|
||||
if (!ret) {
|
||||
cerror(cfg_multicast, "Failed to resolve multicast interface address '%s' of node %s",
|
||||
error("Failed to resolve multicast interface address '%s' of node %s",
|
||||
interface, node_name(n));
|
||||
}
|
||||
}
|
||||
|
||||
int loop;
|
||||
if (!config_setting_lookup_bool(cfg_multicast, "loop", &loop))
|
||||
s->multicast.loop = 0;
|
||||
else
|
||||
s->multicast.loop = loop;
|
||||
|
||||
int ttl;
|
||||
if (!config_setting_lookup_int(cfg_multicast, "ttl", &ttl))
|
||||
s->multicast.ttl = 255;
|
||||
else
|
||||
s->multicast.ttl = ttl;
|
||||
}
|
||||
|
||||
#ifdef WITH_NETEM
|
||||
config_setting_t *cfg_netem;
|
||||
json_t *cfg_netem;
|
||||
|
||||
cfg_netem = config_setting_get_member(cfg, "netem");
|
||||
cfg_netem = json_object_get(cfg, "netem");
|
||||
if (cfg_netem) {
|
||||
int enabled = 1;
|
||||
if (!config_setting_lookup_bool(cfg_netem, "enabled", &enabled) || enabled)
|
||||
tc_parse(cfg_netem, &s->tc_qdisc);
|
||||
|
||||
ret = json_unpack_ex(cfg_netem, &err, 0, "{ s?: b }", "enabled", &enabled);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse setting 'netem' of node %s", node_name(n));
|
||||
|
||||
if (enabled)
|
||||
tc_parse(&s->tc_qdisc, cfg_netem);
|
||||
else
|
||||
s->tc_qdisc = NULL;
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "super_node.h"
|
||||
#include "webmsg.h"
|
||||
#include "webmsg_format.h"
|
||||
|
@ -510,36 +508,41 @@ int websocket_write(struct node *n, struct sample *smps[], unsigned cnt)
|
|||
return cnt;
|
||||
}
|
||||
|
||||
int websocket_parse(struct node *n, config_setting_t *cfg)
|
||||
int websocket_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct websocket *w = n->_vd;
|
||||
config_setting_t *cfg_dests;
|
||||
int ret;
|
||||
|
||||
size_t index;
|
||||
json_t *cfg_dests = NULL;
|
||||
json_t *cfg_dest;
|
||||
json_error_t err;
|
||||
|
||||
list_init(&w->connections);
|
||||
list_init(&w->destinations);
|
||||
|
||||
cfg_dests = config_setting_get_member(cfg, "destinations");
|
||||
if (cfg_dests) {
|
||||
if (!config_setting_is_array(cfg_dests))
|
||||
cerror(cfg_dests, "The 'destinations' setting must be an array of URLs");
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o }", "destinations", &cfg_dests);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_dests); i++) {
|
||||
if (cfg_dests) {
|
||||
if (!json_is_array(cfg_dests))
|
||||
error("The 'destinations' setting of node %s must be an array of URLs", node_name(n));
|
||||
|
||||
json_array_foreach(cfg_dests, index, cfg_dest) {
|
||||
const char *uri, *prot, *ads, *path;
|
||||
|
||||
uri = config_setting_get_string_elem(cfg_dests, i);
|
||||
uri = json_string_value(cfg_dest);
|
||||
if (!uri)
|
||||
cerror(cfg_dests, "The 'destinations' setting must be an array of URLs");
|
||||
error("The 'destinations' setting of node %s must be an array of URLs", node_name(n));
|
||||
|
||||
struct websocket_destination *d = alloc(sizeof(struct websocket_destination));
|
||||
|
||||
d->uri = strdup(uri);
|
||||
if (!d->uri)
|
||||
serror("Failed to allocate memory");
|
||||
|
||||
ret = lws_parse_uri(d->uri, &prot, &ads, &d->info.port, &path);
|
||||
if (ret)
|
||||
cerror(cfg_dests, "Failed to parse websocket URI: '%s'", uri);
|
||||
error("Failed to parse WebSocket URI: '%s'", uri);
|
||||
|
||||
d->info.ssl_connection = !strcmp(prot, "https");
|
||||
d->info.address = strdup(ads);
|
||||
|
|
|
@ -89,83 +89,92 @@ int zeromq_reverse(struct node *n)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int zeromq_parse(struct node *n, config_setting_t *cfg)
|
||||
int zeromq_parse(struct node *n, json_t *cfg)
|
||||
{
|
||||
struct zeromq *z = n->_vd;
|
||||
|
||||
const char *ep, *type, *filter;
|
||||
int ret;
|
||||
const char *ep = NULL;
|
||||
const char *type = NULL;
|
||||
const char *filter = NULL;
|
||||
|
||||
config_setting_t *cfg_pub, *cfg_curve;
|
||||
size_t index;
|
||||
json_t *cfg_pub = NULL;
|
||||
json_t *cfg_curve = NULL;
|
||||
json_t *cfg_val;
|
||||
json_error_t err;
|
||||
|
||||
list_init(&z->publisher.endpoints);
|
||||
|
||||
if (config_setting_lookup_string(cfg, "subscribe", &ep))
|
||||
z->subscriber.endpoint = strdup(ep);
|
||||
else
|
||||
z->subscriber.endpoint = NULL;
|
||||
z->curve.enabled = false;
|
||||
z->ipv6 = 0;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: o, s?: o, s?: s, s?: s, s?: b }",
|
||||
"subscribe", &ep,
|
||||
"publish", &cfg_pub,
|
||||
"curve", &cfg_curve,
|
||||
"filter", &filter,
|
||||
"pattern", &type,
|
||||
"ipv6", &z->ipv6
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse configuration of node %s", node_name(n));
|
||||
|
||||
z->subscriber.endpoint = ep ? strdup(ep) : NULL;
|
||||
z->filter = filter ? strdup(filter) : NULL;
|
||||
|
||||
cfg_pub = config_setting_lookup(cfg, "publish");
|
||||
if (cfg_pub) {
|
||||
switch (config_setting_type(cfg_pub)) {
|
||||
case CONFIG_TYPE_LIST:
|
||||
case CONFIG_TYPE_ARRAY:
|
||||
for (int j = 0; j < config_setting_length(cfg_pub); j++) {
|
||||
const char *ep = config_setting_get_string_elem(cfg_pub, j);
|
||||
switch (json_typeof(cfg_pub)) {
|
||||
case JSON_ARRAY:
|
||||
json_array_foreach(cfg_pub, index, cfg_val) {
|
||||
ep = json_string_value(cfg_pub);
|
||||
if (!ep)
|
||||
error("All 'publish' settings must be strings");
|
||||
|
||||
list_push(&z->publisher.endpoints, strdup(ep));
|
||||
}
|
||||
break;
|
||||
|
||||
case CONFIG_TYPE_STRING:
|
||||
ep = config_setting_get_string(cfg_pub);
|
||||
case JSON_STRING:
|
||||
ep = json_string_value(cfg_pub);
|
||||
|
||||
list_push(&z->publisher.endpoints, strdup(ep));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
cerror(cfg_pub, "Invalid type for ZeroMQ publisher setting");
|
||||
error("Invalid type for ZeroMQ publisher setting");
|
||||
}
|
||||
}
|
||||
|
||||
cfg_curve = config_setting_lookup(cfg, "curve");
|
||||
if (cfg_curve) {
|
||||
if (!config_setting_is_group(cfg_curve))
|
||||
cerror(cfg_curve, "The curve setting must be a group");
|
||||
|
||||
const char *public_key, *secret_key;
|
||||
|
||||
if (!config_setting_lookup_string(cfg_curve, "public_key", &public_key))
|
||||
cerror(cfg_curve, "Setting 'curve.public_key' is missing");
|
||||
z->curve.enabled = true;
|
||||
|
||||
if (!config_setting_lookup_string(cfg_curve, "secret_key", &secret_key))
|
||||
cerror(cfg_curve, "Setting 'curve.secret_key' is missing");
|
||||
|
||||
if (!config_setting_lookup_bool(cfg_curve, "enabled", &z->curve.enabled))
|
||||
z->curve.enabled = true;
|
||||
ret = json_unpack_ex(cfg_curve, &err, 0, "{ s: s, s: s, s?: b }",
|
||||
"public_key", &public_key,
|
||||
"secret_key", &secret_key,
|
||||
"enabled", &z->curve.enabled
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse setting 'curve' of node %s", node_name(n));
|
||||
|
||||
if (strlen(secret_key) != 40)
|
||||
cerror(cfg_curve, "Setting 'curve.secret_key' must be a Z85 encoded CurveZMQ key");
|
||||
error("Setting 'curve.secret_key' of node %s must be a Z85 encoded CurveZMQ key", node_name(n));
|
||||
|
||||
if (strlen(public_key) != 40)
|
||||
cerror(cfg_curve, "Setting 'curve.public_key' must be a Z85 encoded CurveZMQ key");
|
||||
error("Setting 'curve.public_key' of node %s must be a Z85 encoded CurveZMQ key", node_name(n));
|
||||
|
||||
strncpy(z->curve.server.public_key, public_key, 41);
|
||||
strncpy(z->curve.server.secret_key, secret_key, 41);
|
||||
}
|
||||
else
|
||||
z->curve.enabled = false;
|
||||
|
||||
/** @todo We should fix this. Its mostly done. */
|
||||
if (z->curve.enabled)
|
||||
cerror(cfg_curve, "CurveZMQ support is currently broken");
|
||||
error("CurveZMQ support is currently broken");
|
||||
|
||||
if (config_setting_lookup_string(cfg, "filter", &filter))
|
||||
z->filter = strdup(filter);
|
||||
else
|
||||
z->filter = NULL;
|
||||
|
||||
if (config_setting_lookup_string(cfg, "pattern", &type)) {
|
||||
if (type) {
|
||||
if (!strcmp(type, "pubsub"))
|
||||
z->pattern = ZEROMQ_PATTERN_PUBSUB;
|
||||
#ifdef ZMQ_BUILD_DISH
|
||||
|
@ -173,12 +182,9 @@ int zeromq_parse(struct node *n, config_setting_t *cfg)
|
|||
z->pattern = ZEROMQ_PATTERN_RADIODISH;
|
||||
#endif
|
||||
else
|
||||
cerror(cfg, "Invalid type for ZeroMQ node: %s", node_name_short(n));
|
||||
error("Invalid type for ZeroMQ node: %s", node_name_short(n));
|
||||
}
|
||||
|
||||
if (!config_setting_lookup_bool(cfg, "ipv6", &z->ipv6))
|
||||
z->ipv6 = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
40
lib/path.c
40
lib/path.c
|
@ -25,7 +25,6 @@
|
|||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
|
@ -39,6 +38,7 @@
|
|||
#include "memory.h"
|
||||
#include "stats.h"
|
||||
#include "node.h"
|
||||
#include "config_helper.h"
|
||||
|
||||
static void path_read(struct path *p)
|
||||
{
|
||||
|
@ -180,46 +180,51 @@ int path_init(struct path *p, struct super_node *sn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes)
|
||||
int path_parse(struct path *p, json_t *cfg, struct list *nodes)
|
||||
{
|
||||
config_setting_t *cfg_out, *cfg_hooks;
|
||||
const char *in;
|
||||
int ret;
|
||||
const char *in;
|
||||
|
||||
json_error_t err;
|
||||
json_t *cfg_out = NULL;
|
||||
json_t *cfg_hooks = NULL;
|
||||
|
||||
struct node *source;
|
||||
struct list destinations = { .state = STATE_DESTROYED };
|
||||
|
||||
list_init(&destinations);
|
||||
|
||||
/* Input node */
|
||||
if (!config_setting_lookup_string(cfg, "in", &in))
|
||||
cerror(cfg, "Missing input node for path");
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s: s, s?: o, s?: o, s?: b, s?: b, s?: i, s?: i }",
|
||||
"in", &in,
|
||||
"out", &cfg_out,
|
||||
"hooks", &cfg_hooks,
|
||||
"reverse", &p->reverse,
|
||||
"enabled", &p->enabled,
|
||||
"samplelen", &p->samplelen,
|
||||
"queuelen", &p->queuelen
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse path configuration");
|
||||
|
||||
/* Input node */
|
||||
source = list_lookup(nodes, in);
|
||||
if (!source)
|
||||
cerror(cfg, "Invalid input node '%s'", in);
|
||||
jerror(&err, "Invalid input node '%s'", in);
|
||||
|
||||
/* Output node(s) */
|
||||
cfg_out = config_setting_get_member(cfg, "out");
|
||||
if (cfg_out) {
|
||||
ret = node_parse_list(&destinations, cfg_out, nodes);
|
||||
if (ret)
|
||||
cerror(cfg_out, "Failed to parse output nodes");
|
||||
jerror(&err, "Failed to parse output nodes");
|
||||
}
|
||||
|
||||
/* Optional settings */
|
||||
cfg_hooks = config_setting_get_member(cfg, "hooks");
|
||||
if (cfg_hooks) {
|
||||
ret = hook_parse_list(&p->hooks, cfg_hooks, p);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
config_setting_lookup_bool(cfg, "reverse", &p->reverse);
|
||||
config_setting_lookup_bool(cfg, "enabled", &p->enabled);
|
||||
config_setting_lookup_int(cfg, "samplelen", &p->samplelen);
|
||||
config_setting_lookup_int(cfg, "queuelen", &p->queuelen);
|
||||
|
||||
if (!IS_POW2(p->queuelen)) {
|
||||
p->queuelen = LOG2_CEIL(p->queuelen);
|
||||
warn("Queue length should always be a power of 2. Adjusting to %d", p->queuelen);
|
||||
|
@ -242,6 +247,9 @@ int path_parse(struct path *p, config_setting_t *cfg, struct list *nodes)
|
|||
|
||||
list_destroy(&destinations, NULL, false);
|
||||
|
||||
p->cfg = cfg;
|
||||
p->state = STATE_PARSED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <dlfcn.h>
|
||||
|
||||
#include "plugin.h"
|
||||
#include "config_helper.h"
|
||||
|
||||
/** Global list of all known plugins */
|
||||
struct list plugins = { .state = STATE_DESTROYED };
|
||||
|
@ -38,13 +39,15 @@ int plugin_init(struct plugin *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int plugin_parse(struct plugin *p, config_setting_t *cfg)
|
||||
int plugin_parse(struct plugin *p, json_t *cfg)
|
||||
{
|
||||
const char *path;
|
||||
|
||||
path = config_setting_get_string(cfg);
|
||||
path = json_string_value(cfg);
|
||||
if (!path)
|
||||
cerror(cfg, "Setting 'plugin' must be a string.");
|
||||
return -1;
|
||||
|
||||
p->path = strdup(path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -124,7 +124,6 @@ void stats_collect(struct stats_delta *s, struct sample *smps[], size_t cnt)
|
|||
s->last = previous;
|
||||
}
|
||||
|
||||
#ifdef WITH_JSON
|
||||
json_t * stats_json(struct stats *s)
|
||||
{
|
||||
json_t *obj = json_object();
|
||||
|
@ -150,7 +149,6 @@ json_t * stats_json_periodic(struct stats *s, struct path *p)
|
|||
"skipped", s->histograms[STATS_SKIPPED].total
|
||||
);
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
|
||||
void stats_reset(struct stats *s)
|
||||
{
|
||||
|
@ -209,13 +207,11 @@ void stats_print_periodic(struct stats *s, FILE *f, enum stats_format fmt, int v
|
|||
);
|
||||
break;
|
||||
|
||||
#ifdef WITH_JSON
|
||||
case STATS_FORMAT_JSON: {
|
||||
json_t *json_stats = stats_json_periodic(s, p);
|
||||
json_dumpf(json_stats, f, 0);
|
||||
break;
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
|
||||
default: { }
|
||||
}
|
||||
|
@ -233,14 +229,12 @@ void stats_print(struct stats *s, FILE *f, enum stats_format fmt, int verbose)
|
|||
}
|
||||
break;
|
||||
|
||||
#ifdef WITH_JSON
|
||||
case STATS_FORMAT_JSON: {
|
||||
json_t *json_stats = stats_json(s);
|
||||
json_dumpf(json_stats, f, 0);
|
||||
fflush(f);
|
||||
break;
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
|
||||
default: { }
|
||||
}
|
||||
|
|
239
lib/super_node.c
239
lib/super_node.c
|
@ -1,4 +1,4 @@
|
|||
/** Configuration parser.
|
||||
/** The super node object holding the state of the application.
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
|
@ -42,30 +42,10 @@
|
|||
|
||||
#include "kernel/rt.h"
|
||||
|
||||
static void config_dtor(void *data)
|
||||
{
|
||||
if (data)
|
||||
free(data);
|
||||
}
|
||||
|
||||
static int super_node_parse_global(struct super_node *sn, config_setting_t *cfg)
|
||||
{
|
||||
if (!config_setting_is_group(cfg))
|
||||
cerror(cfg, "Global section must be a dictionary.");
|
||||
|
||||
config_setting_lookup_int(cfg, "hugepages", &sn->hugepages);
|
||||
config_setting_lookup_int(cfg, "affinity", &sn->affinity);
|
||||
config_setting_lookup_int(cfg, "priority", &sn->priority);
|
||||
config_setting_lookup_float(cfg, "stats", &sn->stats);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int super_node_init(struct super_node *sn)
|
||||
{
|
||||
assert(sn->state == STATE_DESTROYED);
|
||||
|
||||
log_init(&sn->log, V, LOG_ALL);
|
||||
#ifdef WITH_API
|
||||
api_init(&sn->api, sn);
|
||||
#endif /* WITH_API */
|
||||
|
@ -83,6 +63,9 @@ int super_node_init(struct super_node *sn)
|
|||
sn->stats = 0;
|
||||
sn->hugepages = DEFAULT_NR_HUGEPAGES;
|
||||
|
||||
sn->name = alloc(128); /** @todo missing free */
|
||||
gethostname(sn->name, 128);
|
||||
|
||||
sn->state = STATE_INITIALIZED;
|
||||
|
||||
return 0;
|
||||
|
@ -90,85 +73,81 @@ int super_node_init(struct super_node *sn)
|
|||
|
||||
int super_node_parse_uri(struct super_node *sn, const char *uri)
|
||||
{
|
||||
int ret = CONFIG_FALSE;
|
||||
json_error_t err;
|
||||
|
||||
if (uri) { INDENT
|
||||
FILE *f;
|
||||
AFILE *af;
|
||||
config_setting_t *cfg_root = NULL;
|
||||
|
||||
/* Via stdin */
|
||||
if (!strcmp("-", uri)) {
|
||||
info("Reading configuration from stdin");
|
||||
|
||||
af = NULL;
|
||||
f = stdin;
|
||||
|
||||
info("Reading configuration from stdin");
|
||||
}
|
||||
else {
|
||||
/* Local file? */
|
||||
if (access(uri, F_OK) != -1) {
|
||||
/* Setup libconfig include path.
|
||||
* This is only supported for local files */
|
||||
char *uri_cpy = strdup(uri);
|
||||
char *include_dir = dirname(uri_cpy);
|
||||
|
||||
config_set_include_dir(&sn->cfg, include_dir);
|
||||
|
||||
free(uri_cpy);
|
||||
|
||||
info("Reading configuration from local file: %s", uri);
|
||||
}
|
||||
else
|
||||
info("Reading configuration from URI: %s", uri);
|
||||
info("Reading configuration from URI: %s", uri);
|
||||
|
||||
af = afopen(uri, "r");
|
||||
f = af ? af->file : NULL;
|
||||
if (!af)
|
||||
error("Failed to open configuration from: %s", uri);
|
||||
|
||||
f = af->file;
|
||||
}
|
||||
|
||||
/* Check if file could be loaded / opened */
|
||||
if (!f)
|
||||
error("Failed to open configuration");
|
||||
|
||||
config_init(&sn->cfg);
|
||||
config_set_destructor(&sn->cfg, config_dtor);
|
||||
config_set_auto_convert(&sn->cfg, 1);
|
||||
|
||||
/* Parse config */
|
||||
ret = config_read(&sn->cfg, f);
|
||||
if (ret != CONFIG_TRUE) {
|
||||
#ifdef WITH_JSON
|
||||
/* This does not seem to be a valid libconfig configuration.
|
||||
* Lets try to parse it as JSON instead. */
|
||||
json_error_t err;
|
||||
json_t *json;
|
||||
sn->cfg = json_loadf(f, 0, &err);
|
||||
if (sn->cfg == NULL) {
|
||||
#ifdef WITH_LIBCONFIG
|
||||
int ret;
|
||||
|
||||
json = json_loadf(f, 0, &err);
|
||||
if (json) {
|
||||
ret = json_to_config(json, cfg_root);
|
||||
if (ret)
|
||||
error("Failed t convert JSON to configuration file");
|
||||
config_t cfg;
|
||||
config_setting_t *cfg_root = NULL;
|
||||
|
||||
warn("Failed to parse JSON configuration. Re-trying with old libconfig format.");
|
||||
{ INDENT
|
||||
warn("Please consider migrating to the new format using the 'conf2json' command.");
|
||||
}
|
||||
else {
|
||||
error("Failed to parse configuration");
|
||||
|
||||
config_init(&cfg);
|
||||
config_set_auto_convert(&cfg, 1);
|
||||
|
||||
/* Setup libconfig include path.
|
||||
* This is only supported for local files */
|
||||
if (access(uri, F_OK) != -1) {
|
||||
char *cpy = strdup(uri);
|
||||
|
||||
config_set_include_dir(&cfg, dirname(cpy));
|
||||
|
||||
free(cpy);
|
||||
}
|
||||
|
||||
if (af)
|
||||
arewind(af);
|
||||
else
|
||||
rewind(f);
|
||||
|
||||
ret = config_read(&cfg, f);
|
||||
if (ret != CONFIG_TRUE) {
|
||||
{ INDENT
|
||||
warn("conf: %s in %s:%d", config_error_text(&sn->cfg), uri, config_error_line(&sn->cfg));
|
||||
warn("conf: %s in %s:%d", config_error_text(&cfg), uri, config_error_line(&cfg));
|
||||
warn("json: %s in %s:%d:%d", err.text, err.source, err.line, err.column);
|
||||
}
|
||||
error("Failed to parse configuration");
|
||||
}
|
||||
#else
|
||||
error("Failed to parse configuration");
|
||||
{ INDENT
|
||||
warn("%s in %s:%d", config_error_text(&sn->cfg), uri, config_error_line(&sn->cfg));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Little hack to properly report configuration filename in error messages
|
||||
* We add the uri as a "hook" object to the root setting.
|
||||
* See cerror() on how this info is used.
|
||||
*/
|
||||
cfg_root = config_root_setting(&sn->cfg);
|
||||
config_setting_set_hook(cfg_root, strdup(uri));
|
||||
cfg_root = config_root_setting(&cfg);
|
||||
|
||||
sn->cfg = config_to_json(cfg_root);
|
||||
if (sn->cfg == NULL)
|
||||
error("Failed to convert JSON to configuration file");
|
||||
|
||||
config_destroy(&cfg);
|
||||
#else
|
||||
jerror(&err, "Failed to parse configuration file");
|
||||
#endif /* WITH_LIBCONFIG */
|
||||
}
|
||||
|
||||
/* Close configuration file */
|
||||
if (af)
|
||||
|
@ -176,11 +155,7 @@ int super_node_parse_uri(struct super_node *sn, const char *uri)
|
|||
else if (f != stdin)
|
||||
fclose(f);
|
||||
|
||||
ret = super_node_parse(sn, cfg_root);
|
||||
|
||||
config_destroy(&sn->cfg);
|
||||
|
||||
return ret;
|
||||
return super_node_parse_json(sn, sn->cfg);
|
||||
}
|
||||
else { INDENT
|
||||
warn("No configuration file specified. Starting unconfigured. Use the API to configure this instance.");
|
||||
|
@ -199,105 +174,120 @@ int super_node_parse_cli(struct super_node *sn, int argc, char *argv[])
|
|||
return super_node_parse_uri(sn, uri);
|
||||
}
|
||||
|
||||
int super_node_parse(struct super_node *sn, config_setting_t *cfg)
|
||||
int super_node_parse_json(struct super_node *sn, json_t *cfg)
|
||||
{
|
||||
int ret;
|
||||
const char *name = NULL;
|
||||
|
||||
assert(sn->state != STATE_STARTED);
|
||||
assert(sn->state != STATE_DESTROYED);
|
||||
|
||||
config_setting_t *cfg_nodes, *cfg_paths, *cfg_plugins, *cfg_logging;
|
||||
json_t *cfg_nodes = NULL;
|
||||
json_t *cfg_paths = NULL;
|
||||
json_t *cfg_plugins = NULL;
|
||||
json_t *cfg_logging = NULL;
|
||||
json_t *cfg_web = NULL;
|
||||
|
||||
super_node_parse_global(sn, cfg);
|
||||
json_error_t err;
|
||||
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: o, s?: o, s?: o, s?: o, s?: o, s?: i, s?: i, s?: i, s?: F, s?: s }",
|
||||
"http", &cfg_web,
|
||||
"logging", &cfg_logging,
|
||||
"plugins", &cfg_plugins,
|
||||
"nodes", &cfg_nodes,
|
||||
"paths", &cfg_paths,
|
||||
"hugepages", &sn->hugepages,
|
||||
"affinity", &sn->affinity,
|
||||
"priority", &sn->priority,
|
||||
"stats", &sn->stats,
|
||||
"name", &name
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse global configuration");
|
||||
|
||||
if (name)
|
||||
strncpy(sn->name, name, 128);
|
||||
|
||||
#ifdef WITH_WEB
|
||||
config_setting_t *cfg_web;
|
||||
|
||||
cfg_web = config_setting_get_member(cfg, "http");
|
||||
if (cfg_web)
|
||||
web_parse(&sn->web, cfg_web);
|
||||
#endif /* WITH_WEB */
|
||||
|
||||
/* Parse logging settings */
|
||||
cfg_logging = config_setting_get_member(cfg, "logging");
|
||||
if (cfg_logging)
|
||||
log_parse(&sn->log, cfg_logging);
|
||||
|
||||
/* Parse plugins */
|
||||
cfg_plugins = config_setting_get_member(cfg, "plugins");
|
||||
if (cfg_plugins) {
|
||||
if (!config_setting_is_array(cfg_plugins))
|
||||
cerror(cfg_plugins, "Setting 'plugins' must be a list of strings");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_plugins); i++) {
|
||||
struct config_setting_t *cfg_plugin = config_setting_get_elem(cfg_plugins, i);
|
||||
if (!json_is_array(cfg_plugins))
|
||||
error("Setting 'plugins' must be a list of strings");
|
||||
|
||||
size_t index;
|
||||
json_t *cfg_plugin;
|
||||
json_array_foreach(cfg_plugins, index, cfg_plugin) {
|
||||
struct plugin *p = alloc(sizeof(struct plugin));
|
||||
|
||||
ret = plugin_init(p);
|
||||
if (ret)
|
||||
cerror(cfg_plugin, "Failed to initialize plugin");
|
||||
error("Failed to initialize plugin");
|
||||
|
||||
ret = plugin_parse(p, cfg_plugin);
|
||||
if (ret)
|
||||
cerror(cfg_plugin, "Failed to parse plugin");
|
||||
error("Failed to parse plugin");
|
||||
|
||||
list_push(&sn->plugins, p);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse nodes */
|
||||
cfg_nodes = config_setting_get_member(cfg, "nodes");
|
||||
if (cfg_nodes) {
|
||||
if (!config_setting_is_group(cfg_nodes))
|
||||
warn("Setting 'nodes' must be a group with node name => group mappings.");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_nodes); i++) {
|
||||
config_setting_t *cfg_node = config_setting_get_elem(cfg_nodes, i);
|
||||
if (!json_is_object(cfg_nodes))
|
||||
error("Setting 'nodes' must be a group with node name => group mappings.");
|
||||
|
||||
const char *name;
|
||||
json_t *cfg_node;
|
||||
json_object_foreach(cfg_nodes, name, cfg_node) {
|
||||
struct plugin *p;
|
||||
const char *type;
|
||||
|
||||
/* Required settings */
|
||||
if (!config_setting_lookup_string(cfg_node, "type", &type))
|
||||
cerror(cfg_node, "Missing node type");
|
||||
ret = json_unpack_ex(cfg_node, &err, 0, "{ s: s }", "type", &type);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to parse node");
|
||||
|
||||
p = plugin_lookup(PLUGIN_TYPE_NODE, type);
|
||||
if (!p)
|
||||
cerror(cfg_node, "Invalid node type: %s", type);
|
||||
error("Invalid node type: %s", type);
|
||||
|
||||
struct node *n = alloc(sizeof(struct node));
|
||||
|
||||
ret = node_init(n, &p->node);
|
||||
if (ret)
|
||||
cerror(cfg_node, "Failed to initialize node");
|
||||
error("Failed to initialize node");
|
||||
|
||||
ret = node_parse(n, cfg_node);
|
||||
ret = node_parse(n, cfg_node, name);
|
||||
if (ret)
|
||||
cerror(cfg_node, "Failed to parse node");
|
||||
error("Failed to parse node");
|
||||
|
||||
list_push(&sn->nodes, n);
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse paths */
|
||||
cfg_paths = config_setting_get_member(cfg, "paths");
|
||||
if (cfg_paths) {
|
||||
if (!config_setting_is_list(cfg_paths))
|
||||
if (!json_is_array(cfg_paths))
|
||||
warn("Setting 'paths' must be a list.");
|
||||
|
||||
for (int i = 0; i < config_setting_length(cfg_paths); i++) {
|
||||
config_setting_t *cfg_path = config_setting_get_elem(cfg_paths, i);
|
||||
|
||||
size_t index;
|
||||
json_t *cfg_path;
|
||||
json_array_foreach(cfg_paths, index, cfg_path) {
|
||||
struct path *p = alloc(sizeof(struct path));
|
||||
|
||||
ret = path_init(p, sn);
|
||||
if (ret)
|
||||
cerror(cfg_path, "Failed to init path");
|
||||
error("Failed to initialize path");
|
||||
|
||||
ret = path_parse(p, cfg_path, &sn->nodes);
|
||||
if (ret)
|
||||
cerror(cfg_path, "Failed to parse path");
|
||||
error("Failed to parse path");
|
||||
|
||||
list_push(&sn->paths, p);
|
||||
|
||||
|
@ -306,11 +296,11 @@ int super_node_parse(struct super_node *sn, config_setting_t *cfg)
|
|||
|
||||
ret = path_init(r, sn);
|
||||
if (ret)
|
||||
cerror(cfg_path, "Failed to init path");
|
||||
error("Failed to init path");
|
||||
|
||||
ret = path_reverse(p, r);
|
||||
if (ret)
|
||||
cerror(cfg_path, "Failed to reverse path %s", path_name(p));
|
||||
error("Failed to reverse path %s", path_name(p));
|
||||
|
||||
list_push(&sn->paths, r);
|
||||
}
|
||||
|
@ -455,12 +445,17 @@ int super_node_destroy(struct super_node *sn)
|
|||
|
||||
#ifdef WITH_WEB
|
||||
web_destroy(&sn->web);
|
||||
#endif
|
||||
#endif /* WITH_WEB */
|
||||
#ifdef WITH_API
|
||||
api_destroy(&sn->api);
|
||||
#endif
|
||||
#endif /* WITH_API */
|
||||
|
||||
json_decref(sn->cfg);
|
||||
log_destroy(&sn->log);
|
||||
|
||||
if (sn->name)
|
||||
free(sn->name);
|
||||
|
||||
sn->state = STATE_DESTROYED;
|
||||
|
||||
return 0;
|
||||
|
|
33
lib/web.c
33
lib/web.c
|
@ -20,7 +20,6 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
#include <libconfig.h>
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -28,6 +27,7 @@
|
|||
#include "log.h"
|
||||
#include "web.h"
|
||||
#include "api/session.h"
|
||||
#include "config_helper.h"
|
||||
|
||||
#include "nodes/websocket.h"
|
||||
|
||||
|
@ -168,30 +168,37 @@ int web_init(struct web *w, struct api *a)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int web_parse(struct web *w, config_setting_t *cfg)
|
||||
int web_parse(struct web *w, json_t *cfg)
|
||||
{
|
||||
int enabled = true;
|
||||
const char *ssl_cert, *ssl_private_key, *htdocs;
|
||||
int ret, enabled = 1;
|
||||
const char *ssl_cert = NULL;
|
||||
const char *ssl_private_key = NULL;
|
||||
const char *htdocs = NULL;
|
||||
json_error_t err;
|
||||
|
||||
if (!config_setting_is_group(cfg))
|
||||
cerror(cfg, "Setting 'http' must be a group.");
|
||||
ret = json_unpack_ex(cfg, &err, 0, "{ s?: s, s?: s, s?: s, s?: i, s?: b }",
|
||||
"ssl_cert", &ssl_cert,
|
||||
"ssl_private_key", &ssl_private_key,
|
||||
"htdocs", &htdocs,
|
||||
"port", &w->port,
|
||||
"enabled", &enabled
|
||||
);
|
||||
if (ret)
|
||||
jerror(&err, "Failed to http section of configuration file");
|
||||
|
||||
if (config_setting_lookup_string(cfg, "ssl_cert", &ssl_cert))
|
||||
if (ssl_cert)
|
||||
w->ssl_cert = strdup(ssl_cert);
|
||||
|
||||
if (config_setting_lookup_string(cfg, "ssl_private_key", &ssl_private_key))
|
||||
if (ssl_private_key)
|
||||
w->ssl_private_key = strdup(ssl_private_key);
|
||||
|
||||
if (config_setting_lookup_string(cfg, "htdocs", &htdocs)) {
|
||||
if (htdocs) {
|
||||
if (w->htdocs)
|
||||
free(w->htdocs);
|
||||
|
||||
w->htdocs = strdup(htdocs);
|
||||
}
|
||||
|
||||
config_setting_lookup_int(cfg, "port", &w->port);
|
||||
config_setting_lookup_bool(cfg, "enabled", &enabled);
|
||||
|
||||
if (!enabled)
|
||||
w->port = CONTEXT_PORT_NO_LISTEN;
|
||||
|
||||
|
@ -247,7 +254,7 @@ int web_start(struct web *w)
|
|||
|
||||
int web_stop(struct web *w)
|
||||
{
|
||||
if (w->state == STATE_STARTED)
|
||||
if (w->state != STATE_STARTED)
|
||||
return 0;
|
||||
|
||||
info("Stopping Web sub-system");
|
||||
|
|
|
@ -98,7 +98,6 @@ int web_buffer_read(struct web_buffer *b, char *out, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_JSON
|
||||
int web_buffer_read_json(struct web_buffer *b, json_t **req)
|
||||
{
|
||||
json_error_t e;
|
||||
|
@ -116,7 +115,6 @@ int web_buffer_read_json(struct web_buffer *b, json_t **req)
|
|||
|
||||
return 1;
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
|
||||
int web_buffer_append(struct web_buffer *b, const char *in, size_t len)
|
||||
{
|
||||
|
@ -140,7 +138,6 @@ int web_buffer_append(struct web_buffer *b, const char *in, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef WITH_JSON
|
||||
int web_buffer_append_json(struct web_buffer *b, json_t *res)
|
||||
{
|
||||
size_t len;
|
||||
|
@ -162,4 +159,3 @@ retry: len = json_dumpb(res, b->buffer + b->prefix + b->len, b->size - b->len, 0
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_JSON */
|
||||
|
|
29
src/hook.c
29
src/hook.c
|
@ -37,6 +37,7 @@
|
|||
#include <villas/pool.h>
|
||||
#include <villas/log.h>
|
||||
#include <villas/plugin.h>
|
||||
#include <config_helper.h>
|
||||
|
||||
#include <villas/kernel/rt.h>
|
||||
|
||||
|
@ -103,20 +104,34 @@ int main(int argc, char *argv[])
|
|||
/* Default values */
|
||||
cnt = 1;
|
||||
|
||||
char c;
|
||||
while ((c = getopt(argc, argv, "hv:d:")) != -1) {
|
||||
json_t *cfg_cli = json_object();
|
||||
|
||||
char c, *endptr;
|
||||
while ((c = getopt(argc, argv, "hv:d:f:o:")) != -1) {
|
||||
switch (c) {
|
||||
break;
|
||||
case 'v':
|
||||
cnt = atoi(optarg);
|
||||
break;
|
||||
cnt = strtoul(optarg, &endptr, 0);
|
||||
goto check;
|
||||
case 'd':
|
||||
l.level = atoi(optarg);
|
||||
l.level = strtoul(optarg, &endptr, 0);
|
||||
goto check;
|
||||
case 'o':
|
||||
ret = json_object_extend_str(cfg_cli, optarg);
|
||||
if (ret)
|
||||
error("Invalid option: %s", optarg);
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
case 'h':
|
||||
usage();
|
||||
exit(c == '?' ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
check: if (optarg == endptr)
|
||||
error("Failed to parse parse option argument '-%c %s'", c, optarg);
|
||||
|
||||
}
|
||||
|
||||
if (argc < optind + 1) {
|
||||
|
@ -156,7 +171,7 @@ int main(int argc, char *argv[])
|
|||
if (ret)
|
||||
error("Failed to initialize hook");
|
||||
|
||||
ret = hook_parse_cli(&h, argc - optind - 1, &argv[optind + 1]);
|
||||
ret = hook_parse(&h, cfg_cli);
|
||||
if (ret)
|
||||
error("Failed to parse hook config");
|
||||
|
||||
|
|
|
@ -33,11 +33,11 @@
|
|||
#include <villas/super_node.h>
|
||||
#include <villas/utils.h>
|
||||
#include <villas/node.h>
|
||||
#include <villas/msg.h>
|
||||
#include <villas/timing.h>
|
||||
#include <villas/pool.h>
|
||||
#include <villas/io.h>
|
||||
#include <villas/kernel/rt.h>
|
||||
#include <villas/config_helper.h>
|
||||
|
||||
#include <villas/nodes/websocket.h>
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
#include <criterion/criterion.h>
|
||||
|
||||
#ifdef WITH_LIBCONFIG
|
||||
|
||||
#include <jansson.h>
|
||||
#include <libconfig.h>
|
||||
|
||||
|
@ -114,3 +116,5 @@ Test(utils, json_to_config)
|
|||
|
||||
json_decref(json);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,7 +40,6 @@ static struct vfio_container vc;
|
|||
static void init()
|
||||
{
|
||||
int ret;
|
||||
config_setting_t *cfg_root;
|
||||
|
||||
ret = super_node_init(&sn);
|
||||
cr_assert_eq(ret, 0, "Failed to initialize Supernode");
|
||||
|
@ -51,9 +50,6 @@ static void init()
|
|||
ret = super_node_check(&sn);
|
||||
cr_assert_eq(ret, 0, "Failed to check configuration");
|
||||
|
||||
cfg_root = config_root_setting(&sn.cfg);
|
||||
cr_assert_neq(cfg_root, NULL);
|
||||
|
||||
ret = pci_init(&pci);
|
||||
cr_assert_eq(ret, 0, "Failed to initialize PCI sub-system");
|
||||
|
||||
|
@ -62,7 +58,7 @@ static void init()
|
|||
|
||||
/* Parse FPGA configuration */
|
||||
list_init(&cards);
|
||||
ret = fpga_card_parse_list(&cards, cfg_root);
|
||||
ret = fpga_card_parse_list(&cards, sn.cfg);
|
||||
cr_assert_eq(ret, 0, "Failed to parse FPGA config");
|
||||
|
||||
card = list_lookup(&cards, "vc707");
|
||||
|
@ -120,7 +116,7 @@ Test(fpga, xsg, .description = "XSG: multiply_add")
|
|||
double factor, err = 0;
|
||||
|
||||
struct fpga_ip *ip, *dma;
|
||||
struct model_param *p;
|
||||
struct model_parameter *p;
|
||||
struct dma_mem mem;
|
||||
|
||||
ip = fpga_vlnv_lookup(&card->ips, &(struct fpga_vlnv) { NULL, "sysgen", "xsg_multiply", NULL });
|
||||
|
@ -135,7 +131,7 @@ Test(fpga, xsg, .description = "XSG: multiply_add")
|
|||
if (!p)
|
||||
error("Missing parameter 'factor' for model '%s'", ip->name);
|
||||
|
||||
ret = model_param_read(p, &factor);
|
||||
ret = model_parameter_read(p, &factor);
|
||||
cr_assert_eq(ret, 0, "Failed to read parameter 'factor' from model '%s'", ip->name);
|
||||
|
||||
info("Model param: factor = %f", factor);
|
||||
|
|
99
tests/unit/json.c
Normal file
99
tests/unit/json.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/** Unit tests for libjansson helpers
|
||||
*
|
||||
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
||||
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* @license GNU General Public License (version 3)
|
||||
*
|
||||
* VILLASnode
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************************/
|
||||
|
||||
|
||||
#include <criterion/criterion.h>
|
||||
#include <criterion/parameterized.h>
|
||||
|
||||
#include "config_helper.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct param {
|
||||
const char *desc;
|
||||
const char *json;
|
||||
char *argv[32];
|
||||
};
|
||||
|
||||
ParameterizedTestParameters(json, json_load_cli)
|
||||
{
|
||||
static struct param params[] = {
|
||||
// Combined long option
|
||||
{
|
||||
.argv = { "dummy", "--option=value", NULL },
|
||||
.json = "{ \"option\" : \"value\" }"
|
||||
},
|
||||
// Separated long option
|
||||
{
|
||||
.argv = { "dummy", "--option", "value", NULL },
|
||||
.json = "{ \"option\" : \"value\" }"
|
||||
},
|
||||
// All kinds of data types
|
||||
{
|
||||
.argv = { "dummy", "--integer", "1", "--real", "1.1", "--bool", "true", "--null", "null", "--string", "hello world", NULL },
|
||||
.json = "{ \"integer\" : 1, \"real\" : 1.1, \"bool\" : true, \"null\" : null, \"string\" : \"hello world\" }"
|
||||
},
|
||||
// Array generation
|
||||
{
|
||||
.argv = { "dummy", "--bool", "true", "--bool", "false", NULL },
|
||||
.json = "{ \"bool\" : [ true, false ] }"
|
||||
},
|
||||
// Dots in the option name generate sub objects
|
||||
{
|
||||
.argv = { "dummy", "--sub.option", "value", NULL },
|
||||
.json = "{ \"sub\" : { \"option\" : \"value\" } }"
|
||||
},
|
||||
// Nesting is possible
|
||||
{
|
||||
.argv = { "dummy", "--sub.sub.option", "value", NULL },
|
||||
.json = "{ \"sub\" : { \"sub\" : { \"option\" : \"value\" } } }"
|
||||
},
|
||||
// Multiple subgroups are merged
|
||||
{
|
||||
.argv = { "dummy", "--sub.sub.option", "value1", "--sub.option", "value2", NULL },
|
||||
.json = "{ \"sub\" : { \"option\" : \"value2\", \"sub\" : { \"option\" : \"value1\" } } }"
|
||||
}
|
||||
};
|
||||
|
||||
return cr_make_param_array(struct param, params, ARRAY_LEN(params));
|
||||
}
|
||||
|
||||
ParameterizedTest(struct param *p, json, json_load_cli)
|
||||
{
|
||||
json_error_t err;
|
||||
json_t *json, *cli;
|
||||
|
||||
/* Calculate argc */
|
||||
int argc = 0;
|
||||
while (p->argv[argc])
|
||||
argc++;
|
||||
|
||||
json = json_loads(p->json, 0, &err);
|
||||
cr_assert_not_null(json);
|
||||
|
||||
cli = json_load_cli(argc, p->argv);
|
||||
cr_assert_not_null(cli);
|
||||
|
||||
//json_dumpf(json, stdout, JSON_INDENT(2)); putc('\n', stdout);
|
||||
//json_dumpf(cli, stdout, JSON_INDENT(2)); putc('\n', stdout);
|
||||
|
||||
cr_assert(json_equal(json, cli));
|
||||
}
|
Loading…
Add table
Reference in a new issue