1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/node/ synced 2025-03-09 00:00:00 +01:00

added first part of new node type: OPAL_ASYNC

This node type allows starting the S2SS server as an asynchronous
process from RT-LAB.
This commit is contained in:
Steffen Vogel 2015-03-12 22:56:58 +01:00
parent c42163366f
commit 273e71b973
7 changed files with 203 additions and 24 deletions

View file

@ -73,25 +73,27 @@ int config_parse_path(config_setting_t *cfg,
/** Parse a single node and add it to the global configuration.
*
* @param cfg A libconfig object pointing to the node
* @param nodes Add new nodes to this linked list
* @param cfg A libconfig object pointing to the node.
* @param nodes Add new nodes to this linked list.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int config_parse_node(config_setting_t *cfg,
struct node **nodes);
int config_parse_node(config_setting_t *cfg, struct node **nodes);
/** Parse node connection details for OPAL type
*
* @param cfg A libconfig object pointing to the node
* @param argc The CLI argument count as used in main().
* @param argv The CLI argument list as used in main(), containing shmem parameters.
* @param n A pointer to the node structure which should be parsed.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
int config_parse_opal(config_setting_t *cfg, struct node *n);
int config_parse_opal(int argc, char *argv[], struct node *n);
/** Parse node connection details for GTFPGA type
*
* @param cfg A libconfig object pointing to the node
* @param cfg A libconfig object pointing to the node.
* @param n A pointer to the node structure which should be parsed.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
@ -99,7 +101,8 @@ int config_parse_gtfpga(config_setting_t *cfg, struct node *n);
/** Parse node connection details for SOCKET type
*
* @param cfg A libconfig object pointing to the node
* @param cfg A libconfig object pointing to the node.
* @param n A pointer to the node structure which should be parsed.
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/
@ -107,8 +110,8 @@ int config_parse_socket(config_setting_t *cfg, struct node *n);
/** Parse network emulator (netem) settings.
*
* @param cfg A libconfig object containing the settings
* @param em A pointer to the settings
* @param cfg A libconfig object containing the settings.
* @param em A pointer to the netem settings structure (part of the path structure).
* @retval 0 Success. Everything went well.
* @retval <0 Error. Something went wrong.
*/

View file

@ -39,7 +39,7 @@ enum node_type {
UDP, /* BSD socket: AF_INET SOCK_DGRAM */
TCPD, /* BSD socket: AF_INET SOCK_STREAM bind + listen + accept */
TCP, /* BSD socket: AF_INET SOCK_STREAM bind + connect */
// OPAL_ASYNC, /* OPAL-RT AsyncApi */
OPAL_ASYNC, /* OPAL-RT AsyncApi */
// GTFPGA, /* Xilinx ML507 GTFPGA card */
INVALID
};
@ -118,10 +118,14 @@ int node_stop(struct node *n);
/** Lookup string representation of socket type
*
* @param type A string describing the socket type. This must be one of: tcp, tcpd, udp, ip, ieee802.3
* @return An enumeration value or INVALID (0)
* You can either provide a node type in string or enum representation.
* Set str to NULL, to use the enum type.
*
* @param str A string describing the socket type. This must be one of: tcp, tcpd, udp, ip, ieee802.3
* @param enu The enum type of the socket.
* @return A pointer to the vtable, or NULL if there is no socket type / vtable with this id.
*/
struct node_vtable const * node_lookup_vtable(const char *str);
struct node_vtable const * node_lookup_vtable(const char *str, struct node_type enu);
/** Search list of nodes for a name.
*

View file

@ -9,8 +9,36 @@
#ifndef _OPAL_H_
#define _OPAL_H_
struct opal {
/* Define RTLAB before including OpalPrint.h for messages to be sent
* to the OpalDisplay. Otherwise stdout will be used. */
#define RTLAB
#include "OpalPrint.h"
#include "AsyncApi.h"
/* This is just for initializing the shared memory access to communicate
* with the RT-LAB model. It's easier to remember the arguments like this */
#define OPAL_ASYNC_SHMEM_NAME argv[1]
#define OPAL_ASYNC_SHMEM_SIZE atoi(argv[2])
#define OPAL_PRINT_SHMEM_NAME argv[3]
struct opal {
Opal_GenAsyncParam_Ctrl icon_ctrl;
char * async_shmem_name;
char * print_shmem_name;
int async_shmem_size;
};
int opal_parse(int argc, char *argv[], struct node *n);
int opal_print(struct node *n, char *buf, int len);
int opal_open(struct node *n);
int opal_close(struct node *n);
int opal_read(struct node *n, struct msg *m);
int opal_write(struct node *n, struct msg *m);
#endif /* _OPAL_H_ */

View file

@ -184,6 +184,9 @@ int config_parse_node(config_setting_t *cfg, struct node **nodes)
n->vt = node_lookup_vtable(type);
if (!n->vt)
cerror(cfg, "Invalid type for node '%s'", n->name);
if (!n->vt->parse)
cerror(cfg, "Node type '%s' is not allowed in the config", type);
}
else
n->vt = node_lookup_vtable("udp");
@ -196,8 +199,29 @@ int config_parse_node(config_setting_t *cfg, struct node **nodes)
}
/** @todo Implement */
int config_parse_opal(config_setting_t *cfg, struct node *n)
int config_parse_opal(int argc, char *argv[], struct node *n)
{
n->cfg = NULL;
n->name = "opal";
n->type = OPAL_ASYNC;
n->vt = node_lookup_table(NULL, n->type);
struct opal *o = (struct opal *) malloc(sizeof(struct opal));
if (!o)
error("Failed to allocate memory for opal settings");
memset(o, 0, sizeof(opal));
o->async_shmem_name = OPAL_ASYNC_SHMEM_NAME;
o->async_shmem_size = OPAL_ASYNC_SHMEM_SIZE;
o->print_shmem_name = OPAL_PRINT_SHMEM_NAME;
int err;
if ((err = OpalGetAsyncCtrlParameters(&o->icon_ctrl, sizeof(IconCtrlStruct))) != EOK)
error("Could not get controller parameters (%d).\n", PROGNAME, err);
n->opal = o;
return 0;
}
@ -214,7 +238,7 @@ int config_parse_socket(config_setting_t *cfg, struct node *n)
struct socket *s = (struct socket *) malloc(sizeof(struct socket));
if (!s)
serror("Failed to allocate memory for socket");
serror("Failed to allocate memory for socket settings");
memset(s, 0, sizeof(struct socket));

View file

@ -24,13 +24,14 @@
/** Vtable for virtual node sub types */
static const struct node_vtable vtables[] = {
#ifdef ENABLE_OPAL_ASYNC
{ OPAL_ASYNC, "opal", NULL, opal_print, opal_open, opal_close, opal_read, opal_write },
#endif
VTABLE(IEEE_802_3, "ieee802.3", socket),
VTABLE(IP, "ip", socket),
VTABLE(UDP, "udp", socket),
VTABLE(TCP, "tcp", socket),
VTABLE(TCPD, "tcpd", socket),
//VTABLE(OPAL, "opal", opal ),
//VTABLE(GTFPGA, "gtfpga", gtfpga),
VTABLE(TCPD, "tcpd", socket)
};
/** Linked list of nodes */
@ -46,11 +47,17 @@ struct node * node_lookup_name(const char *str, struct node *nodes)
return NULL;
}
struct node_vtable const * node_lookup_vtable(const char *str)
struct node_vtable const * node_lookup_vtable(const char *str, struct node_type enu)
{
for (int i = 0; i < ARRAY_LEN(vtables); i++) {
if (!strcmp(vtables[i].name, str))
return &vtables[i];
if (str) {
if (!strcmp(vtables[i].name, str))
return &vtables[i];
}
else {
if (vtables[i].type == enu)
return &vtables[i];
}
}
return NULL;

View file

@ -7,3 +7,90 @@
*/
#include "opal.h"
int opal_print(struct node *n, char *buf, int len)
{
}
int opal_open(struct node *n)
{
/* Enable the OpalPrint function. This prints to the OpalDisplay. */
if (OpalSystemCtrl_Register(PRINT_SHMEM_NAME) != EOK) {
printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME);
exit(EXIT_FAILURE);
}
OpalPrint("%s: This is a S2SS client\n", PROGNAME);
/* Open Share Memory created by the model. */
if ((OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME)) != EOK) {
OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME);
exit(EXIT_FAILURE);
}
}
int opal_close(struct node *n)
{
OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME);
OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME);
}
int opal_read(struct node *n, struct msg *m)
{
/* This call unblocks when the 'Data Ready' line of a send icon is asserted. */
if ((n = OpalWaitForAsyncSendRequest(&SendID)) != EOK) {
ModelState = OpalGetAsyncModelState();
if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) {
OpalSetAsyncSendIconError(n, SendID);
OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, n);
}
return -1; // FIXME: correct return value
}
/* No errors encountered yet */
OpalSetAsyncSendIconError(0, SendID);
/* Get the size of the data being sent by the unblocking SendID */
OpalGetAsyncSendIconDataLength(&mdldata_size, SendID);
if (mdldata_size / sizeof(double) > MSG_VALUES) {
OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n",
PROGNAME, SendID, MSG_VALUES);
return NULL;
}
/* Read data from the model */
OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID);
msg.sequence = htons(seq++);
msg.length = mdldata_size / sizeof(double);
for (i = 0; i < msg.length; i++)
msg.data[i].f = (float) mdldata[i];
msg_size = MSG_LEN(msg.length);
/* This next call allows the execution of the "asynchronous" process
* to actually be synchronous with the model. To achieve this, you
* should set the "Sending Mode" in the Async_Send block to
* NEED_REPLY_BEFORE_NEXT_SEND or NEED_REPLY_NOW. This will force
* the model to wait for this process to call this
* OpalAsyncSendRequestDone function before continuing. */
OpalAsyncSendRequestDone(SendID);
/* Before continuing, we make sure that the real-time model
* has not been stopped. If it has, we quit. */
ModelState = OpalGetAsyncModelState();
if ((ModelState == STATE_RESET) || (ModelState == STATE_STOP))
return -1; // TODO: fixme
return 0;
}
int opal_write(struct node *n, struct msg *m)
{
}

View file

@ -116,9 +116,15 @@ int main(int argc, char *argv[])
BLD(YEL(VERSION)), BLD(MAG(__DATE__)), BLD(MAG(__TIME__)));
/* Check arguments */
#ifndef ENABLE_OPAL_ASYNC
if (argc != 2)
#else
if (argc != 2 || argc != 4)
#endif
usage(argv[0]);
char *configfile = argv[1];
/* Check priviledges */
if (getuid() != 0)
error("The server requires superuser privileges!");
@ -131,8 +137,28 @@ int main(int argc, char *argv[])
info("Parsing configuration:");
config_init(&config);
#ifdef ENABLE_OPAL_ASYNC
/* Check if called as asynchronous process from RT-LAB */
if (argc == 4) {
/* Allocate memory */
struct node *n = (struct node *) malloc(sizeof(struct node));
if (!n)
error("Failed to allocate memory for node");
memset(n, 0, sizeof(struct node));
config_parse_node_opal(argc, argv, n);
configfile = n->opal->icon_ctrl.StringParam[0];
if (configfile && strlen(configfile))
info("Found config file supplied by Opal Async process: '%s'", configfile);
list_add(*nodes, n);
}
#endif
/* Parse configuration and create nodes/paths */
config_parse(argv[1], &config, &settings, &nodes, &paths);
config_parse(configfile, &config, &settings, &nodes, &paths);
/* Connect all nodes and start one thread per path */
info("Starting nodes:");