/** Nodes. * * @author Steffen Vogel * @copyright 2016, Institute for Automation of Complex Power Systems, EONERC *********************************************************************************/ #include #include #include "sample.h" #include "node.h" #include "cfg.h" #include "utils.h" #include "config.h" /** List of registered node-types */ struct list node_types = LIST_INIT(); int node_read(struct node *n, struct sample *smps[], unsigned cnt) { int nread = 0; if (!n->_vt->read) return -1; /* Send in parts if vector not supported */ if (n->_vt->vectorize > 0 && n->_vt->vectorize < cnt) { while (cnt - nread > 0) { nread += n->_vt->read(n, &smps[nread], MIN(cnt - nread, n->_vt->vectorize)); } } else { nread = n->_vt->read(n, smps, cnt); } for (int i = 0; i < nread; i++) smps[i]->source = n; return nread; } int node_write(struct node *n, struct sample *smps[], unsigned cnt) { int nsent = 0; if (!n->_vt->write) return -1; /* Send in parts if vector not supported */ if (n->_vt->vectorize > 0 && n->_vt->vectorize < cnt) { while (cnt - nsent > 0) nsent += n->_vt->write(n, &smps[nsent], MIN(cnt - nsent, n->_vt->vectorize)); } else { nsent = n->_vt->write(n, smps, cnt); } return nsent; } int node_init(struct node_type *vt, int argc, char *argv[], config_setting_t *cfg) { int ret; if (vt->state != NODE_TYPE_UNINITIALIZED) return -1; info("Initializing " YEL("%s") " node type", vt->name); { INDENT ret = vt->init ? vt->init(argc, argv, cfg) : -1; } if (ret == 0) vt->state = NODE_TYPE_INITIALIZED; return ret; } int node_deinit(struct node_type *vt) { int ret; if (vt->state != NODE_TYPE_INITIALIZED) return -1; info("De-initializing " YEL("%s") " node type", vt->name); { INDENT ret = vt->deinit ? vt->deinit() : -1; } if (ret == 0) vt->state = NODE_TYPE_UNINITIALIZED; return ret; } int node_start(struct node *n) { int ret; if (n->state != NODE_CREATED && n->state != NODE_STOPPED) return -1; n->state = NODE_STARTING; info("Starting node %s", node_name_long(n)); { INDENT ret = n->_vt->open ? n->_vt->open(n) : -1; } if (ret == 0) n->state = NODE_RUNNING; n->sequence = 0; return ret; } int node_stop(struct node *n) { int ret; if (n->state != NODE_RUNNING) return -1; n->state = NODE_STOPPING; info("Stopping node %s", node_name(n)); { INDENT ret = n->_vt->close ? n->_vt->close(n) : -1; } if (ret == 0) n->state = NODE_STOPPED; return ret; } char * node_name(struct node *n) { if (!n->_name) strcatf(&n->_name, RED("%s") "(" YEL("%s") ")", n->name, n->_vt->name); return n->_name; } char * node_name_long(struct node *n) { if (!n->_name_long) { if (n->_vt->print) { char *name_long = n->_vt->print(n); strcatf(&n->_name_long, "%s: %s", node_name(n), name_long); free(name_long); } else n->_name_long = node_name(n); } return n->_name_long; } const char * node_name_short(struct node *n) { return n->name; } const char * node_name_type(struct node *n) { return n->_vt->name; } int node_reverse(struct node *n) { return n->_vt->reverse ? n->_vt->reverse(n) : -1; } struct node * node_create(struct node_type *vt) { struct node *n = alloc(sizeof(struct node)); list_push(&vt->instances, n); n->_vt = vt; n->_vd = alloc(n->_vt->size); if (n->_vt->create) n->_vt->create(n); n->state = NODE_CREATED; return n; } void node_destroy(struct node *n) { if (n->_vt->destroy) n->_vt->destroy(n); list_remove(&n->_vt->instances, n); free(n->_vd); free(n->_name); free(n); } /** Parse an array or single node and checks if they exist in the "nodes" section. * * Examples: * out = [ "sintef", "scedu" ] * out = "acs" * * @param cfg The libconfig object handle for "out". * @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) { const char *str; struct node *node; 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"); 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); 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)); list_push(list, node); } else cerror(cfg, "Invalid outgoing node"); } break; default: cerror(cfg, "Invalid output node(s)"); } return list_length(list); } int node_parse(struct node *n, config_setting_t *cfg, struct settings *set) { struct node_type *vt; const char *type, *name; int ret; name = config_setting_name(cfg); if (!config_setting_lookup_string(cfg, "type", &type)) cerror(cfg, "Missing node type"); vt = list_lookup(&node_types, type); if (!vt) cerror(cfg, "Invalid type for node '%s'", config_setting_name(cfg)); n->name = name; n->cfg = cfg; ret = n->_vt->parse ? n->_vt->parse(n, cfg) : 0; if (ret) cerror(cfg, "Failed to parse node '%s'", node_name(n)); if (config_setting_lookup_int(cfg, "vectorize", &n->vectorize)) { config_setting_t *cfg_vectorize = config_setting_lookup(cfg, "vectorize"); if (n->vectorize <= 0) cerror(cfg_vectorize, "Invalid value for `vectorize` %d. Must be natural number!", n->vectorize); if (vt->vectorize && vt->vectorize < n->vectorize) cerror(cfg_vectorize, "Invalid value for `vectorize`. Node type %s requires a number smaller than %d!", node_name_type(n), vt->vectorize); } else n->vectorize = 1; if (!config_setting_lookup_int(cfg, "affinity", &n->affinity)) n->affinity = set->affinity; return ret; }