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:
parent
c42163366f
commit
273e71b973
7 changed files with 203 additions and 24 deletions
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -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:");
|
||||
|
|
Loading…
Add table
Reference in a new issue