From 1c95caac50cdd6f4640250fbd8a88732c75e8364 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 23 Apr 2017 22:11:55 +0200 Subject: [PATCH 01/16] simplified socket packet format by removing endianess flag: all values are now in network byte-order --- .../models/send_receive/include/msg_format.h | 83 ++++++------------- include/villas/msg_format.h | 43 ++-------- include/villas/webmsg_format.h | 46 ++-------- 3 files changed, 44 insertions(+), 128 deletions(-) diff --git a/clients/opal/udp/models/send_receive/include/msg_format.h b/clients/opal/udp/models/send_receive/include/msg_format.h index 2b1b5cc79..f3adff5d6 100644 --- a/clients/opal/udp/models/send_receive/include/msg_format.h +++ b/clients/opal/udp/models/send_receive/include/msg_format.h @@ -5,93 +5,64 @@ * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC *********************************************************************************/ -#ifndef _MSG_FORMAT_H_ -#define _MSG_FORMAT_H_ +#pragma once #include -#ifdef __linux__ - #define _BSD_SOURCE 1 - #include -#elif defined(__PPC__) /* Xilinx toolchain */ - #include -#endif - -#include "config.h" - -/** Maximum number of dword values in a message */ -#define MSG_VALUES MAX_VALUES - /** The current version number for the message format */ -#define MSG_VERSION 1 +#define MSG_VERSION 2 /** @todo Implement more message types */ #define MSG_TYPE_DATA 0 /**< Message contains float values */ #define MSG_TYPE_START 1 /**< Message marks the beginning of a new simulation case */ #define MSG_TYPE_STOP 2 /**< Message marks the end of a simulation case */ -#define MSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */ -#define MSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */ +/** The total size in bytes of a message */ +#define MSG_LEN(values) (sizeof(struct msg) + MSG_DATA_LEN(values)) -#if BYTE_ORDER == LITTLE_ENDIAN - #define MSG_ENDIAN_HOST MSG_ENDIAN_LITTLE -#elif BYTE_ORDER == BIG_ENDIAN - #define MSG_ENDIAN_HOST MSG_ENDIAN_BIG -#else - #error "Unknown byte order!" -#endif +/** The length of \p values values in bytes. */ +#define MSG_DATA_LEN(values) (sizeof(float) * (values)) -/** The total length of a message */ -#define MSG_LEN(msg) (4 * ((msg)->length + 4)) +/** The offset to the first data value in a message. */ +#define MSG_DATA_OFFSET(msg) ((char *) (msg) + offsetof(struct msg, data)) +/** Initialize a message with default values */ +#define MSG_INIT(len, seq) (struct msg) {\ + .version = MSG_VERSION, \ + .type = MSG_TYPE_DATA, \ + .length = len, \ + .sequence = seq \ +} + +/** The timestamp of a message in struct timespec format */ #define MSG_TS(msg) (struct timespec) { \ .tv_sec = (msg)->ts.sec, \ .tv_nsec = (msg)->ts.nsec \ } -/** Initialize a message */ -#define MSG_INIT(i) (struct msg) { \ - .version = MSG_VERSION, \ - .type = MSG_TYPE_DATA, \ - .endian = MSG_ENDIAN_HOST, \ - .length = i, \ - .sequence = 0, \ - .rsvd1 = 0, .rsvd2 = 0 \ -} - /** This message format is used by all clients * * @diafile msg_format.dia **/ struct msg { -#if BYTE_ORDER == BIG_ENDIAN unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ - unsigned endian : 1; /**< Specifies the byteorder of the message (see MSG_ENDIAN_*) */ - unsigned rsvd1 : 1; /**< Reserved bits */ -#elif BYTE_ORDER == LITTLE_ENDIAN - unsigned rsvd1 : 1; /**< Reserved bits */ - unsigned endian : 1; /**< Specifies the byteorder of the message (see MSG_ENDIAN_*) */ - unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ - unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ -#endif + unsigned rsvd1 : 2; /**< Reserved bits */ unsigned rsvd2 : 8; /**< Reserved bits */ - uint16_t length; /**< The number of values in msg::data[]. Endianess is specified in msg::endian. */ - uint32_t sequence; /**< The sequence number is incremented by one for consecutive messages. Endianess is specified in msg::endian. */ + uint16_t length; /**< The number of values in msg::data[]. */ + uint32_t sequence; /**< The sequence number is incremented by one for consecutive messages. */ - /** A timestamp per message. Endianess is specified in msg::endian. */ + /** A timestamp per message. */ struct { - uint32_t sec; /**< Seconds since 1970-01-01 00:00:00 */ + uint32_t sec; /**< Seconds since 1970-01-01 00:00:00 */ uint32_t nsec; /**< Nanoseconds of the current second. */ } ts; - /** The message payload. Endianess is specified in msg::endian. */ + /** The message payload. */ union { - float f; /**< Floating point values (note msg::endian) */ - uint32_t i; /**< Integer values (note msg::endian) */ - } data[MSG_VALUES]; -} __attribute__((aligned(64), packed)); - -#endif /* _MSG_FORMAT_H_ */ + float f; /**< Floating point values. */ + uint32_t i; /**< Integer values. */ + } data[]; +} __attribute__((packed)); \ No newline at end of file diff --git a/include/villas/msg_format.h b/include/villas/msg_format.h index e63f90db0..f3adff5d6 100644 --- a/include/villas/msg_format.h +++ b/include/villas/msg_format.h @@ -9,32 +9,14 @@ #include -#ifdef __linux__ - #define _BSD_SOURCE 1 - #include -#elif defined(__PPC__) /* Xilinx toolchain */ - #include -#endif - /** The current version number for the message format */ -#define MSG_VERSION 1 +#define MSG_VERSION 2 /** @todo Implement more message types */ #define MSG_TYPE_DATA 0 /**< Message contains float values */ #define MSG_TYPE_START 1 /**< Message marks the beginning of a new simulation case */ #define MSG_TYPE_STOP 2 /**< Message marks the end of a simulation case */ -#define MSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */ -#define MSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */ - -#if BYTE_ORDER == LITTLE_ENDIAN - #define MSG_ENDIAN_HOST MSG_ENDIAN_LITTLE -#elif BYTE_ORDER == BIG_ENDIAN - #define MSG_ENDIAN_HOST MSG_ENDIAN_BIG -#else - #error "Unknown byte order!" -#endif - /** The total size in bytes of a message */ #define MSG_LEN(values) (sizeof(struct msg) + MSG_DATA_LEN(values)) @@ -48,7 +30,6 @@ #define MSG_INIT(len, seq) (struct msg) {\ .version = MSG_VERSION, \ .type = MSG_TYPE_DATA, \ - .endian = MSG_ENDIAN_HOST, \ .length = len, \ .sequence = seq \ } @@ -65,31 +46,23 @@ **/ struct msg { -#if BYTE_ORDER == BIG_ENDIAN unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ - unsigned endian : 1; /**< Specifies the byteorder of the message (see MSG_ENDIAN_*) */ - unsigned rsvd1 : 1; /**< Reserved bits */ -#elif BYTE_ORDER == LITTLE_ENDIAN - unsigned rsvd1 : 1; /**< Reserved bits */ - unsigned endian : 1; /**< Specifies the byteorder of the message (see MSG_ENDIAN_*) */ - unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ - unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ -#endif + unsigned rsvd1 : 2; /**< Reserved bits */ unsigned rsvd2 : 8; /**< Reserved bits */ - uint16_t length; /**< The number of values in msg::data[]. Endianess is specified in msg::endian. */ - uint32_t sequence; /**< The sequence number is incremented by one for consecutive messages. Endianess is specified in msg::endian. */ + uint16_t length; /**< The number of values in msg::data[]. */ + uint32_t sequence; /**< The sequence number is incremented by one for consecutive messages. */ - /** A timestamp per message. Endianess is specified in msg::endian. */ + /** A timestamp per message. */ struct { uint32_t sec; /**< Seconds since 1970-01-01 00:00:00 */ uint32_t nsec; /**< Nanoseconds of the current second. */ } ts; - /** The message payload. Endianess is specified in msg::endian. */ + /** The message payload. */ union { - float f; /**< Floating point values (note msg::endian) */ - uint32_t i; /**< Integer values (note msg::endian) */ + float f; /**< Floating point values. */ + uint32_t i; /**< Integer values. */ } data[]; } __attribute__((packed)); \ No newline at end of file diff --git a/include/villas/webmsg_format.h b/include/villas/webmsg_format.h index 19b600de6..8978bdba1 100644 --- a/include/villas/webmsg_format.h +++ b/include/villas/webmsg_format.h @@ -11,34 +11,14 @@ #include -#include "msg_format.h" - -#ifdef __linux__ - #define _BSD_SOURCE 1 - #include -#elif defined(__PPC__) /* Xilinx toolchain */ - #include -#endif - /** The current version number for the message format */ -#define WEBMSG_VERSION 1 +#define WEBMSG_VERSION 2 /** @todo Implement more message types */ #define WEBMSG_TYPE_DATA 0 /**< Message contains float values */ #define WEBMSG_TYPE_START 1 /**< Message marks the beginning of a new simulation case */ #define WEBMSG_TYPE_STOP 2 /**< Message marks the end of a simulation case */ -#define WEBMSG_ENDIAN_LITTLE 0 /**< Message values are in little endian format (float too!) */ -#define WEBMSG_ENDIAN_BIG 1 /**< Message values are in bit endian format */ - -#if BYTE_ORDER == LITTLE_ENDIAN - #define WEBMSG_ENDIAN_HOST MSG_ENDIAN_LITTLE -#elif BYTE_ORDER == BIG_ENDIAN - #define WEBMSG_ENDIAN_HOST MSG_ENDIAN_BIG -#else - #error "Unknown byte order!" -#endif - /** The total size in bytes of a message */ #define WEBMSG_LEN(values) (sizeof(struct webmsg) + MSG_DATA_LEN(values)) @@ -69,33 +49,25 @@ **/ struct webmsg { -#if BYTE_ORDER == BIG_ENDIAN unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ - unsigned endian : 1; /**< Specifies the byteorder of the message (see MSG_ENDIAN_*) */ - unsigned rsvd1 : 1; /**< Reserved bits */ -#elif BYTE_ORDER == LITTLE_ENDIAN - unsigned rsvd1 : 1; /**< Reserved bits */ - unsigned endian : 1; /**< Specifies the byteorder of the message (see MSG_ENDIAN_*) */ - unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ - unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ -#endif + unsigned rsvd1 : 2; /**< Reserved bits */ - uint8_t id; /**< The node index from / to which this sample received / sent to. + uint8_t id; /**< The node index from / to which this sample received / sent to. * Corresponds to the index of the node in the http://localhost/nodes.json array. */ - uint16_t length; /**< The number of values in msg::data[]. Endianess is specified in msg::endian. */ - uint32_t sequence; /**< The sequence number is incremented by one for consecutive messages. Endianess is specified in msg::endian. */ + uint16_t length; /**< The number of values in msg::data[]. */ + uint32_t sequence; /**< The sequence number is incremented by one for consecutive messages. */ - /** A timestamp per message. Endianess is specified in msg::endian. */ + /** A timestamp per message. */ struct { uint32_t sec; /**< Seconds since 1970-01-01 00:00:00 */ uint32_t nsec; /**< Nanoseconds of the current second. */ } ts; - /** The message payload. Endianess is specified in msg::endian. */ + /** The message payload. */ union { - float f; /**< Floating point values (note msg::endian) */ - uint32_t i; /**< Integer values (note msg::endian) */ + float f; /**< Floating point values. */ + uint32_t i; /**< Integer values. */ } data[]; } __attribute__((packed)); \ No newline at end of file From d6f2697e1b88b7c38a7e22cff7c5082f33d165b9 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 23 Apr 2017 22:12:10 +0200 Subject: [PATCH 02/16] added new helper functions to convert struct msg between network and host byte-order --- .../udp/models/send_receive/include/msg.h | 30 ++++++------ .../opal/udp/models/send_receive/src/msg.c | 46 ++++++++++------- include/villas/msg.h | 24 +++++---- lib/msg.c | 49 ++++++++++++------- 4 files changed, 86 insertions(+), 63 deletions(-) diff --git a/clients/opal/udp/models/send_receive/include/msg.h b/clients/opal/udp/models/send_receive/include/msg.h index ee00377ab..7988d21b2 100644 --- a/clients/opal/udp/models/send_receive/include/msg.h +++ b/clients/opal/udp/models/send_receive/include/msg.h @@ -1,27 +1,28 @@ -/** Message related functions. +/** Message related functions * * @file * @author Steffen Vogel * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC *********************************************************************************/ -#ifndef _MSG_H_ -#define _MSG_H_ +#pragma once -#include "msg_format.h" +/* Forward declarations. */ +struct msg; -/** Swaps message contents byte-order. +/** Swaps the byte-order of the message. * - * Message can either be transmitted in little or big endian - * format. The actual endianess for a message is defined by the - * msg::endian field. This covers msg::length, msg::sequence, msg::data and msg::ts fields. - * Received message are usally converted to the endianess of the host. - * This is required for further sanity checks of the sequence number - * or parsing of the data. + * Message are always transmitted in network (big endian) byte order. * * @param m A pointer to the message */ -void msg_swap(struct msg *m); +void msg_hdr_ntoh(struct msg *m); + +void msg_hdr_hton(struct msg *m); + +void msg_ntoh(struct msg *m); + +void msg_hton(struct msg *m); /** Check the consistency of a message. * @@ -31,7 +32,4 @@ void msg_swap(struct msg *m); * @retval 0 The message header is valid. * @retval <0 The message header is invalid. */ -int msg_verify(struct msg *m); - -#endif /* _MSG_H_ */ - +int msg_verify(struct msg *m); \ No newline at end of file diff --git a/clients/opal/udp/models/send_receive/src/msg.c b/clients/opal/udp/models/send_receive/src/msg.c index dd472514e..c61a16345 100644 --- a/clients/opal/udp/models/send_receive/src/msg.c +++ b/clients/opal/udp/models/send_receive/src/msg.c @@ -4,27 +4,41 @@ * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC *********************************************************************************/ -#ifdef __linux__ - #include -#elif defined(__PPC__) /* Xilinx toolchain */ - #include - #define bswap_16(x) Xil_EndianSwap16(x) - #define bswap_32(x) Xil_EndianSwap32(x) -#endif +#include #include "msg.h" +#include "msg_format.h" -void msg_swap(struct msg *m) +void msg_ntoh(struct msg *m) { - m->length = bswap_16(m->length); - m->sequence = bswap_32(m->sequence); - m->ts.sec = bswap_32(m->ts.sec); - m->ts.nsec = bswap_32(m->ts.nsec); + msg_hdr_ntoh(m); for (int i = 0; i < m->length; i++) - m->data[i].i = bswap_32(m->data[i].i); + m->data[i].i = ntohl(m->data[i].i); +} - m->endian ^= 1; +void msg_hton(struct msg *m) +{ + for (int i = 0; i < m->length; i++) + m->data[i].i = htonl(m->data[i].i); + + msg_hdr_hton(m); +} + +void msg_hdr_hton(struct msg *m) +{ + m->length = htons(m->length); + m->sequence = htonl(m->sequence); + m->ts.sec = htonl(m->ts.sec); + m->ts.nsec = htonl(m->ts.nsec); +} + +void msg_hdr_ntoh(struct msg *m) +{ + m->length = ntohs(m->length); + m->sequence = ntohl(m->sequence); + m->ts.sec = ntohl(m->ts.sec); + m->ts.nsec = ntohl(m->ts.nsec); } int msg_verify(struct msg *m) @@ -33,10 +47,8 @@ int msg_verify(struct msg *m) return -1; else if (m->type != MSG_TYPE_DATA) return -2; - else if ((m->length <= 0) || (m->length > MSG_VALUES)) - return -3; else if ((m->rsvd1 != 0) || (m->rsvd2 != 0)) - return -4; + return -3; else return 0; } \ No newline at end of file diff --git a/include/villas/msg.h b/include/villas/msg.h index 130e06be1..7988d21b2 100644 --- a/include/villas/msg.h +++ b/include/villas/msg.h @@ -7,24 +7,22 @@ #pragma once -#include +/* Forward declarations. */ +struct msg; -#include "msg_format.h" - -struct node; - -/** Swaps the byte order of the header part of struct msg. +/** Swaps the byte-order of the message. * - * Message can either be transmitted in little or big endian - * format. The actual endianess for a message is defined by the - * msg::endian field. This covers msg::length, msg::sequence, msg::data and msg::ts fields. - * Received message are usally converted to the endianess of the host. - * This is required for further sanity checks of the sequence number - * or parsing of the data. + * Message are always transmitted in network (big endian) byte order. * * @param m A pointer to the message */ -void msg_hdr_swap(struct msg *m); +void msg_hdr_ntoh(struct msg *m); + +void msg_hdr_hton(struct msg *m); + +void msg_ntoh(struct msg *m); + +void msg_hton(struct msg *m); /** Check the consistency of a message. * diff --git a/lib/msg.c b/lib/msg.c index 006fae1a6..c61a16345 100644 --- a/lib/msg.c +++ b/lib/msg.c @@ -4,26 +4,41 @@ * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC *********************************************************************************/ -#ifdef __linux__ - #include -#elif defined(__PPC__) /* Xilinx toolchain */ - #include - #define bswap_16(x) Xil_EndianSwap16(x) - #define bswap_32(x) Xil_EndianSwap32(x) -#endif +#include #include "msg.h" -#include "node.h" -#include "utils.h" +#include "msg_format.h" -void msg_hdr_swap(struct msg *m) +void msg_ntoh(struct msg *m) { - m->length = bswap_16(m->length); - m->sequence = bswap_32(m->sequence); - m->ts.sec = bswap_32(m->ts.sec); - m->ts.nsec = bswap_32(m->ts.nsec); + msg_hdr_ntoh(m); + + for (int i = 0; i < m->length; i++) + m->data[i].i = ntohl(m->data[i].i); +} - m->endian ^= 1; +void msg_hton(struct msg *m) +{ + for (int i = 0; i < m->length; i++) + m->data[i].i = htonl(m->data[i].i); + + msg_hdr_hton(m); +} + +void msg_hdr_hton(struct msg *m) +{ + m->length = htons(m->length); + m->sequence = htonl(m->sequence); + m->ts.sec = htonl(m->ts.sec); + m->ts.nsec = htonl(m->ts.nsec); +} + +void msg_hdr_ntoh(struct msg *m) +{ + m->length = ntohs(m->length); + m->sequence = ntohl(m->sequence); + m->ts.sec = ntohl(m->ts.sec); + m->ts.nsec = ntohl(m->ts.nsec); } int msg_verify(struct msg *m) @@ -32,8 +47,8 @@ int msg_verify(struct msg *m) return -1; else if (m->type != MSG_TYPE_DATA) return -2; - else if ((m->rsvd1 != 0) || (m->rsvd2 != 0)) + else if ((m->rsvd1 != 0) || (m->rsvd2 != 0)) return -3; else return 0; -} +} \ No newline at end of file From a3222da312ca2e821d4740cdc4e1ac73a54e2d5c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 23 Apr 2017 21:54:24 +0200 Subject: [PATCH 03/16] adapted socket node-type to support new packet format --- include/villas/nodes/socket.h | 6 +- lib/nodes/socket.c | 483 +++++++++++++++++----------------- 2 files changed, 244 insertions(+), 245 deletions(-) diff --git a/include/villas/nodes/socket.h b/include/villas/nodes/socket.h index 542fcb404..1d08dcb25 100644 --- a/include/villas/nodes/socket.h +++ b/include/villas/nodes/socket.h @@ -42,7 +42,11 @@ union sockaddr_union { struct socket { int sd; /**> The socket descriptor */ int mark; /**> Socket mark for netem, routing and filtering */ - int endian; /** Endianness of the data sent/received by the node */ + + enum { + SOCKET_ENDIAN_LITTLE, + SOCKET_ENDIAN_BIG + } endian; /** Endianness of the data sent/received by the node */ enum socket_layer layer; /**> The OSI / IP layer which should be used for this socket */ enum socket_header header; /**> Payload header type */ diff --git a/lib/nodes/socket.c b/lib/nodes/socket.c index 7ed72305c..33899b749 100644 --- a/lib/nodes/socket.c +++ b/lib/nodes/socket.c @@ -9,14 +9,7 @@ #include #include #include - -#ifdef __linux__ - #include -#elif defined(__PPC__) /* Xilinx toolchain */ - #include - #define bswap_16(x) Xil_EndianSwap16(x) - #define bswap_32(x) Xil_EndianSwap32(x) -#endif +#include #include "nodes/socket.h" #include "config.h" @@ -26,6 +19,7 @@ #include "kernel/nl.h" #include "kernel/tc.h" #include "msg.h" +#include "msg_format.h" #include "sample.h" #include "queue.h" #include "plugin.h" @@ -126,8 +120,8 @@ char * socket_print(struct node *n) endian = "auto"; else { switch (s->endian) { - case MSG_ENDIAN_LITTLE: endian = "little"; break; - case MSG_ENDIAN_BIG: endian = "big"; break; + case SOCKET_ENDIAN_LITTLE: endian = "little"; break; + case SOCKET_ENDIAN_BIG: endian = "big"; break; } } @@ -231,254 +225,255 @@ int socket_destroy(struct node *n) return 0; } +static int socket_read_none(struct node *n, struct sample *smps[], unsigned cnt) +{ + ssize_t bytes; + int length; + struct socket *s = n->_vd; + + /* The GTNETv2-SKT protocol send every sample in a single packet. + * socket_read() receives a single packet. */ + int iov_len = s->header == SOCKET_HEADER_FAKE ? 2 : 1; + struct iovec iov[iov_len]; + struct sample *smp = smps[0]; + + if (cnt < 1) + return 0; + + uint32_t header[3]; + if (s->header == SOCKET_HEADER_FAKE) { + iov[0].iov_base = header; + iov[0].iov_len = sizeof(header); + } + + /* Remaining values are payload */ + iov[iov_len-1].iov_base = &smp->data; + iov[iov_len-1].iov_len = SAMPLE_DATA_LEN(smp->capacity); + + struct msghdr mhdr = { + .msg_iov = iov, + .msg_iovlen = iov_len, + .msg_name = (struct sockaddr *) &s->remote, + .msg_namelen = sizeof(s->remote) + }; + + /* Receive next sample */ + bytes = recvmsg(s->sd, &mhdr, MSG_TRUNC); + if (bytes == 0) + error("Remote node %s closed the connection", node_name(n)); /** @todo Should we really hard fail here? */ + else if (bytes < 0) + serror("Failed recv from node %s", node_name(n)); + else if (bytes % 4 != 0) { + warn("Packet size is invalid: %zd Must be multiple of 4 bytes.", bytes); + recv(s->sd, NULL, 0, 0); /* empty receive buffer */ + return -1; + } + + /* Convert message to host endianess */ + for (int i = 0; i < ARRAY_LEN(header); i++) + header[i] = s->endian == SOCKET_ENDIAN_BIG + ? be32toh(header[i]) + : le32toh(header[i]); + + for (int i = 0; i < bytes / SAMPLE_DATA_LEN(1); i++) + smp->data[i].i = s->endian == SOCKET_ENDIAN_BIG + ? be32toh(smp->data[i].i) + : le32toh(smp->data[i].i); + + if (s->header == SOCKET_HEADER_FAKE) + length = (bytes - sizeof(header)) / SAMPLE_DATA_LEN(1); + else + length = bytes / SAMPLE_DATA_LEN(1); + + if (length > smp->capacity) { + warn("Node %s received more values than supported. Dropping %u values", node_name(n), length - smp->capacity); + length = smp->capacity; + } + + if (s->header == SOCKET_HEADER_FAKE) { + smp->sequence = header[0]; + smp->ts.origin.tv_sec = header[1]; + smp->ts.origin.tv_nsec = header[2]; + } + else { + smp->sequence = n->sequence++; /* Fake sequence no generated by VILLASnode */ + smp->ts.origin.tv_sec = -1; + smp->ts.origin.tv_nsec = -1; + } + + smp->ts.received.tv_sec = -1; + smp->ts.received.tv_nsec = -1; + + smp->length = length; + + return 1; /* GTNET-SKT sends every sample in a single packet */ +} + +static int socket_read_villas(struct node *n, struct sample *smps[], unsigned cnt) +{ + struct socket *s = n->_vd; + + int ret; + ssize_t bytes; + + /* Peak into message header of the first sample and to get total packet size. */ + bytes = recv(s->sd, NULL, 0, MSG_PEEK | MSG_TRUNC); + if (bytes < MSG_LEN(1) || bytes % 4 != 0) { + warn("Received invalid packet for node %s", node_name(n)); + recv(s->sd, NULL, 0, 0); /* empty receive buffer */ + return -1; + } + + char data[bytes]; + + /* Receive message from socket */ + bytes = recv(s->sd, data, bytes, 0); + if (bytes == 0) + error("Remote node %s closed the connection", node_name(n)); + else if (bytes < 0) + serror("Failed receive packet from node %s", node_name(n)); + + int received = 0; + char *ptr = data; + + struct msg *msg = (struct msg *) ptr; + struct sample *smp = smps[received]; + + while (ptr < data + bytes - sizeof(struct msg) && received < cnt) { + msg_ntoh(msg); + + ret = msg_verify(msg); + if (ret) { + warn("Received invalid packet for node %s", node_name(n)); + return -1; + } + + smp->length = msg->length; + smp->sequence = msg->sequence; + smp->ts.origin = MSG_TS(msg); + smp->ts.received.tv_sec = -1; + smp->ts.received.tv_nsec = -1; + + memcpy(smp->data, msg->data, SAMPLE_DATA_LEN(msg->length)); + + ptr += MSG_LEN(msg->length); + + msg = (struct msg *) ptr; + smp = smps[++received]; + } + + return received; +} + +static int socket_write_none(struct node *n, struct sample *smps[], unsigned cnt) +{ + struct socket *s = n->_vd; + + int sent = 0; + ssize_t bytes; + + if (cnt < 1) + return 0; + + for (int i = 0; i < cnt; i++) { + int off = s->header == SOCKET_HEADER_FAKE ? 3 : 0; + int len = smps[i]->length + off; + uint32_t data[len]; + + /* First three values are sequence, seconds and nano-seconds timestamps */ + if (s->header == SOCKET_HEADER_FAKE) { + data[0] = smps[i]->sequence; + data[1] = smps[i]->ts.origin.tv_sec; + data[2] = smps[i]->ts.origin.tv_nsec; + } + + for (int j = 0; j < smps[i]->length; j++) + data[off + j] = s->endian == SOCKET_ENDIAN_BIG + ? htobe32(smps[i]->data[j].i) + : htole32(smps[i]->data[j].i); + + bytes = sendto(s->sd, data, len * sizeof(data[0]), 0, + (struct sockaddr *) &s->remote, sizeof(s->remote)); + if (bytes < 0) + serror("Failed send to node %s", node_name(n)); + + sent++; + } + + return sent; +} + +static int socket_write_villas(struct node *n, struct sample *smps[], unsigned cnt) +{ + struct socket *s = n->_vd; + + ssize_t bytes = 0; + + for (int i = 0; i < cnt; i++) + bytes += MSG_LEN(smps[i]->length); + + char data[bytes], *ptr = data; + + struct msg *msg = (struct msg *) ptr; + + for (int i = 0; i < cnt; i++) { + *msg = MSG_INIT(smps[i]->length, smps[i]->sequence); + + msg->ts.sec = smps[i]->ts.origin.tv_sec; + msg->ts.nsec = smps[i]->ts.origin.tv_nsec; + + memcpy(msg->data, smps[i]->data, MSG_DATA_LEN(smps[i]->length)); + + msg_hton(msg); + + ptr += MSG_LEN(msg->length); + + msg = (struct msg *) ptr; + } + + /* Send message */ + bytes = sendto(s->sd, data, bytes, 0, (struct sockaddr *) &s->remote, sizeof(s->remote)); + if (bytes < 0) + serror("Failed send to node %s", node_name(n)); + + return cnt; +} + int socket_read(struct node *n, struct sample *smps[], unsigned cnt) { struct socket *s = n->_vd; - int samples, ret, received, length; - ssize_t bytes; - - if (s->header == SOCKET_HEADER_NONE || s->header == SOCKET_HEADER_FAKE) { - if (cnt < 1) - return 0; - - /* The GTNETv2-SKT protocol send every sample in a single packet. - * socket_read() receives a single packet. */ - int iov_len = s->header == SOCKET_HEADER_FAKE ? 2 : 1; - struct iovec iov[iov_len]; - struct sample *smp = smps[0]; - - uint32_t header[3]; - if (s->header == SOCKET_HEADER_FAKE) { - iov[0].iov_base = header; - iov[0].iov_len = sizeof(header); - } - - /* Remaining values are payload */ - iov[iov_len-1].iov_base = &smp->data; - iov[iov_len-1].iov_len = SAMPLE_DATA_LEN(smp->capacity); + switch (s->header) { + case SOCKET_HEADER_NONE: + case SOCKET_HEADER_FAKE: + return socket_read_none(n, smps, cnt); - struct msghdr mhdr = { - .msg_iov = iov, - .msg_iovlen = iov_len, - .msg_name = (struct sockaddr *) &s->remote, - .msg_namelen = sizeof(s->remote) - }; - - /* Receive next sample */ - bytes = recvmsg(s->sd, &mhdr, MSG_TRUNC); - if (bytes == 0) - error("Remote node %s closed the connection", node_name(n)); /** @todo Should we really hard fail here? */ - else if (bytes < 0) - serror("Failed recv from node %s", node_name(n)); - else if (bytes % 4 != 0) { - warn("Packet size is invalid: %zd Must be multiple of 4 bytes.", bytes); - recv(s->sd, NULL, 0, 0); /* empty receive buffer */ - return -1; - } - - /* Convert message to host endianess */ - if (s->endian != MSG_ENDIAN_HOST) { - for (int i = 0; i < ARRAY_LEN(header); i++) - header[i] = bswap_32(header[i]); - - for (int i = 0; i < bytes / SAMPLE_DATA_LEN(1); i++) - smp->data[i].i = bswap_32(smp->data[i].i); - } - - if (s->header == SOCKET_HEADER_FAKE) - length = (bytes - sizeof(header)) / SAMPLE_DATA_LEN(1); - else - length = bytes / SAMPLE_DATA_LEN(1); - - if (length > smp->capacity) { - warn("Node %s received more values than supported. Dropping %u values", node_name(n), length - smp->capacity); - length = smp->capacity; - } - - if (s->header == SOCKET_HEADER_FAKE) { - smp->sequence = header[0]; - smp->ts.origin.tv_sec = header[1]; - smp->ts.origin.tv_nsec = header[2]; - } - else { - smp->sequence = n->sequence++; /* Fake sequence no generated by VILLASnode */ - smp->ts.origin.tv_sec = -1; - smp->ts.origin.tv_nsec = -1; - } - - smp->ts.received.tv_sec = -1; - smp->ts.received.tv_nsec = -1; - - smp->length = length; - - received = 1; /* GTNET-SKT sends every sample in a single packet */ - } - else { - struct msg msgs[cnt]; - struct msg hdr; - struct iovec iov[2*cnt]; - struct msghdr mhdr = { - .msg_iov = iov - }; - - /* Peak into message header of the first sample and to get total packet size. */ - bytes = recv(s->sd, &hdr, sizeof(struct msg), MSG_PEEK | MSG_TRUNC); - if (bytes < sizeof(struct msg) || bytes % 4 != 0) { - warn("Packet size is invalid: %zd Must be multiple of 4 bytes.", bytes); - recv(s->sd, NULL, 0, 0); /* empty receive buffer */ - return -1; - } - - ret = msg_verify(&hdr); - if (ret) { - warn("Invalid message received: reason=%d, bytes=%zd", ret, bytes); - recv(s->sd, NULL, 0, 0); /* empty receive buffer */ - return -1; - } - - /* Convert message to host endianess */ - if (hdr.endian != MSG_ENDIAN_HOST) - msg_hdr_swap(&hdr); - - samples = bytes / MSG_LEN(hdr.length); - if (samples > cnt) { - warn("Node %s received more samples than supported. Dropping %u samples", node_name(n), samples - cnt); - samples = cnt; - } - - /* We expect that all received samples have the same amount of values! */ - for (int i = 0; i < samples; i++) { - iov[2*i+0].iov_base = &msgs[i]; - iov[2*i+0].iov_len = MSG_LEN(0); - - iov[2*i+1].iov_base = SAMPLE_DATA_OFFSET(smps[i]); - iov[2*i+1].iov_len = SAMPLE_DATA_LEN(hdr.length); - - mhdr.msg_iovlen += 2; - - if (hdr.length > smps[i]->capacity) - error("Node %s received more values than supported. Dropping %d values.", node_name(n), hdr.length - smps[i]->capacity); - } - - /* Receive message from socket */ - bytes = recvmsg(s->sd, &mhdr, 0); //--? samples - cnt samples dropped - if (bytes == 0) - error("Remote node %s closed the connection", node_name(n)); - else if (bytes < 0) - serror("Failed recv from node %s", node_name(n)); - - for (received = 0; received < samples; received++) { - struct msg *m = &msgs[received]; - struct sample *smp = smps[received]; - - ret = msg_verify(m); - if (ret) - break; - - if (m->length != hdr.length) - break; - - /* Convert message to host endianess */ - if (m->endian != MSG_ENDIAN_HOST) { - msg_hdr_swap(m); - - for (int i = 0; i < m->length; i++) - smp->data[i].i = bswap_32(smp->data[i].i); - } - - smp->length = m->length; - smp->sequence = m->sequence; - smp->ts.origin = MSG_TS(m); - smp->ts.received.tv_sec = -1; - smp->ts.received.tv_nsec = -1; - } + case SOCKET_HEADER_DEFAULT: + return socket_read_villas(n, smps, cnt); } - debug(LOG_SOCKET | 17, "Received message of %zd bytes: %u samples", bytes, received); - - return received; + return -1; } int socket_write(struct node *n, struct sample *smps[], unsigned cnt) { struct socket *s = n->_vd; - ssize_t bytes; - int sent = 0; - /* Construct iovecs */ - if (s->header == SOCKET_HEADER_NONE || s->header == SOCKET_HEADER_FAKE) { - if (cnt < 1) - return 0; - - for (int i = 0; i < cnt; i++) { - int off = s->header == SOCKET_HEADER_FAKE ? 3 : 0; - int len = smps[i]->length + off; - uint32_t data[len]; - - /* First three values are sequence, seconds and nano-seconds timestamps */ - if (s->header == SOCKET_HEADER_FAKE) { - data[0] = smps[i]->sequence; - data[1] = smps[i]->ts.origin.tv_sec; - data[2] = smps[i]->ts.origin.tv_nsec; - } - - for (int j = 0; j < smps[i]->length; j++) { - if (s->endian == MSG_ENDIAN_HOST) - data[off + j] = smps[i]->data[j].i; - else - data[off + j] = bswap_32(smps[i]->data[j].i); - } - - bytes = sendto(s->sd, data, len * sizeof(data[0]), 0, - (struct sockaddr *) &s->remote, sizeof(s->remote)); - if (bytes < 0) - serror("Failed send to node %s", node_name(n)); - - sent++; - - debug(LOG_SOCKET | 17, "Sent packet of %zd bytes with 1 sample", bytes); - } + switch (s->header) { + case SOCKET_HEADER_NONE: + case SOCKET_HEADER_FAKE: + return socket_write_none(n, smps, cnt); + + case SOCKET_HEADER_DEFAULT: + return socket_write_villas(n, smps, cnt); } - else { - struct msg msgs[cnt]; - struct iovec iov[2*cnt]; - struct msghdr mhdr = { - .msg_iov = iov, - .msg_iovlen = ARRAY_LEN(iov), - .msg_name = (struct sockaddr *) &s->remote, - .msg_namelen = sizeof(s->remote) - }; - - for (int i = 0; i < cnt; i++) { - - msgs[i] = MSG_INIT(smps[i]->length, smps[i]->sequence); - - msgs[i].ts.sec = smps[i]->ts.origin.tv_sec; - msgs[i].ts.nsec = smps[i]->ts.origin.tv_nsec; - - iov[i*2+0].iov_base = &msgs[i]; - iov[i*2+0].iov_len = MSG_LEN(0); - - iov[i*2+1].iov_base = SAMPLE_DATA_OFFSET(smps[i]); - iov[i*2+1].iov_len = SAMPLE_DATA_LEN(smps[i]->length); - } - - /* Send message */ - bytes = sendmsg(s->sd, &mhdr, 0); - if (bytes < 0) - serror("Failed send to node %s", node_name(n)); - - sent = cnt; /** @todo Find better way to determine how many values we actually sent */ - - debug(LOG_SOCKET | 17, "Sent packet of %zd bytes with %u samples", bytes, cnt); - } - - return sent; + + return -1; } int socket_parse(struct node *n, config_setting_t *cfg) { + config_setting_t *cfg_netem; const char *local, *remote, *layer, *hdr, *endian; int ret; @@ -513,12 +508,12 @@ int socket_parse(struct node *n, config_setting_t *cfg) } if (!config_setting_lookup_string(cfg, "endian", &endian)) - s->endian = MSG_ENDIAN_BIG; + s->endian = SOCKET_ENDIAN_BIG; else { if (!strcmp(endian, "big") || !strcmp(endian, "network")) - s->endian = MSG_ENDIAN_BIG; + s->endian = SOCKET_ENDIAN_BIG; else if (!strcmp(endian, "little")) - s->endian = MSG_ENDIAN_LITTLE; + s->endian = SOCKET_ENDIAN_LITTLE; else cerror(cfg, "Invalid endianness type '%s' for node %s", endian, node_name(n)); } @@ -541,7 +536,7 @@ int socket_parse(struct node *n, config_setting_t *cfg) remote, node_name(n), gai_strerror(ret)); } - config_setting_t *cfg_netem = config_setting_get_member(cfg, "netem"); + cfg_netem = config_setting_get_member(cfg, "netem"); if (cfg_netem) { int enabled = 1; if (!config_setting_lookup_bool(cfg_netem, "enabled", &enabled) || enabled) From df0ee8d98af48bc2892c7a8fb53cd23c077839cd Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 23 Apr 2017 22:15:41 +0200 Subject: [PATCH 04/16] adapted AsyncIP for new endianess --- clients/opal/udp/models/send_receive/src/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 744399482..e12c03380 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -139,6 +139,8 @@ static void *SendToIPPort(void *arg) msg.sequence = seq++; msg.ts.sec = now.tv_sec; msg.ts.nsec = now.tv_nsec; + + msg_hton(msg); /* Perform the actual write to the ip port */ if (SendPacket((char *) &msg, MSG_LEN(&msg)) < 0) @@ -207,16 +209,13 @@ static void *RecvFromIPPort(void *arg) OpalPrint("%s: Received message with unknown version. Skipping..\n", PROGNAME); continue; } + msg_ntoh(msg); if (msg.type != MSG_TYPE_DATA) { OpalPrint("%s: Received no data. Skipping..\n", PROGNAME); continue; } - /* Convert message to host endianess */ - if (msg.endian != MSG_ENDIAN_HOST) - msg_swap(&msg); - if (n != MSG_LEN(&msg)) { OpalPrint("%s: Received incoherent packet (size: %d, complete: %d)\n", PROGNAME, n, MSG_LEN(&msg)); continue; From f59d2ccf1b2dc33e409a5878d2f9c09e45d67fa1 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Sun, 23 Apr 2017 22:16:26 +0200 Subject: [PATCH 05/16] cleanup coding style --- .../opal/udp/models/send_receive/src/main.c | 117 +++++++------ .../opal/udp/models/send_receive/src/socket.c | 164 +++++++----------- .../opal/udp/models/send_receive/src/utils.c | 51 ++---- 3 files changed, 135 insertions(+), 197 deletions(-) diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index e12c03380..2ecd769e3 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ /* This is the message format */ #include "config.h" #include "msg.h" +#include "msg_format.h" #include "socket.h" #include "utils.h" @@ -53,6 +55,7 @@ #define PRINT_SHMEM_NAME argv[3] #ifdef _DEBUG // TODO: workaround + #define CPU_TICKS 3466948000 struct msg *msg_send = NULL; @@ -75,23 +78,22 @@ void Tick(int sig, siginfo_t *si, void *ptr) } #endif /* _DEBUG */ -static void *SendToIPPort(void *arg) +static void * SendToIPPort(void *arg) { - unsigned int SendID = 1; - unsigned int ModelState; - unsigned int i, n; - int nbSend = 0; + unsigned int ModelState, SendID = 1, i, n; + int nbSend = 0, ret; uint32_t seq = 0; /* Data from OPAL-RT model */ - double mdldata[MSG_VALUES]; + double mdldata[MAX_VALUES]; int mdldata_size; /* Data from VILLASnode */ - struct msg msg = MSG_INIT(0); + char buf[MSG_LEN(MAX_VALUES)]; + struct msg *msg = (struct msg *) buf; #ifdef _DEBUG // TODO: workaround - msg_send = &msg; + msg_send = msg; #endif /* _DEBUG */ OpalPrint("%s: SendToIPPort thread started\n", PROGNAME); @@ -104,7 +106,8 @@ static void *SendToIPPort(void *arg) do { /* This call unblocks when the 'Data Ready' line of a send icon is asserted. */ - if ((n = OpalWaitForAsyncSendRequest(&SendID)) != EOK) { + n = OpalWaitForAsyncSendRequest(&SendID); + if (n != EOK) { ModelState = OpalGetAsyncModelState(); if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { OpalSetAsyncSendIconError(n, SendID); @@ -119,9 +122,9 @@ static void *SendToIPPort(void *arg) /* Get the size of the data being sent by the unblocking SendID */ OpalGetAsyncSendIconDataLength(&mdldata_size, SendID); - if (mdldata_size / sizeof(double) > MSG_VALUES) { + if (mdldata_size / sizeof(double) > MAX_VALUES) { OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n", - PROGNAME, SendID, MSG_VALUES); + PROGNAME, SendID, MAX_VALUES); return NULL; } @@ -132,18 +135,19 @@ static void *SendToIPPort(void *arg) struct timespec now; clock_gettime(CLOCK_REALTIME, &now); - msg.length = mdldata_size / sizeof(double); - for (i = 0; i < msg.length; i++) - msg.data[i].f = (float) mdldata[i]; + msg->length = mdldata_size / sizeof(double); + for (i = 0; i < msg->length; i++) + msg->data[i].f = (float) mdldata[i]; - msg.sequence = seq++; - msg.ts.sec = now.tv_sec; - msg.ts.nsec = now.tv_nsec; + msg->sequence = seq++; + msg->ts.sec = now.tv_sec; + msg->ts.nsec = now.tv_nsec; msg_hton(msg); /* Perform the actual write to the ip port */ - if (SendPacket((char *) &msg, MSG_LEN(&msg)) < 0) + ret = SendPacket((char *) msg, MSG_LEN(msg->length)); + if (ret < 0) OpalSetAsyncSendIconError(errno, SendID); else OpalSetAsyncSendIconError(0, SendID); @@ -166,19 +170,18 @@ static void *SendToIPPort(void *arg) return NULL; } -static void *RecvFromIPPort(void *arg) +static void * RecvFromIPPort(void *arg) { - unsigned RecvID = 1; - unsigned i, n; - int nbRecv = 0; - unsigned ModelState; + unsigned int ModelState, RecvID = 1, i, n; + int nbRecv = 0, ret; /* Data from OPAL-RT model */ - double mdldata[MSG_VALUES]; + double mdldata[MAX_VALUES]; int mdldata_size; /* Data from VILLASnode */ - struct msg msg = MSG_INIT(0); + char buf[MSG_LEN(MAX_VALUES)]; + struct msg *msg = (struct msg *) buf; OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME); @@ -190,7 +193,7 @@ static void *RecvFromIPPort(void *arg) do { /* Receive message */ - n = RecvPacket((char *) &msg, sizeof(msg), 1.0); + n = RecvPacket((char *) msg, sizeof(buf), 1.0); if (n < 1) { ModelState = OpalGetAsyncModelState(); if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { @@ -204,41 +207,32 @@ static void *RecvFromIPPort(void *arg) break; } - /* Check message contents */ - if (msg.version != MSG_VERSION) { - OpalPrint("%s: Received message with unknown version. Skipping..\n", PROGNAME); - continue; - } msg_ntoh(msg); - if (msg.type != MSG_TYPE_DATA) { - OpalPrint("%s: Received no data. Skipping..\n", PROGNAME); - continue; - } - - if (n != MSG_LEN(&msg)) { - OpalPrint("%s: Received incoherent packet (size: %d, complete: %d)\n", PROGNAME, n, MSG_LEN(&msg)); + ret = msg_verify(msg); + if (ret) { + OpalPrint("%s: Skipping invalid packet\n", PROGNAME); continue; } /* Update OPAL model */ - OpalSetAsyncRecvIconStatus(msg.sequence, RecvID); /* Set the Status to the message ID */ + OpalSetAsyncRecvIconStatus(msg->sequence, RecvID); /* Set the Status to the message ID */ OpalSetAsyncRecvIconError(0, RecvID); /* Set the Error to 0 */ /* Get the number of signals to send back to the model */ OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID); - if (mdldata_size / sizeof(double) > MSG_VALUES) { + if (mdldata_size / sizeof(double) > MAX_VALUES) { OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n", - PROGNAME, RecvID, mdldata_size / sizeof(double), MSG_VALUES); + PROGNAME, RecvID, mdldata_size / sizeof(double), MAX_VALUES); return NULL; } - if (mdldata_size / sizeof(double) > msg.length) + if (mdldata_size / sizeof(double) > msg->length) OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n", - PROGNAME, RecvID, mdldata_size / sizeof(double), msg.length); + PROGNAME, RecvID, mdldata_size / sizeof(double), msg->length); - for (i = 0; i < msg.length; i++) - mdldata[i] = (double) msg.data[i].f; + for (i = 0; i < msg->length; i++) + mdldata[i] = (double) msg->data[i].f; OpalSetAsyncRecvIconData(mdldata, mdldata_size, RecvID); @@ -254,7 +248,7 @@ static void *RecvFromIPPort(void *arg) int main(int argc, char *argv[]) { - int err; + int ret; Opal_GenAsyncParam_Ctrl IconCtrlStruct; @@ -276,24 +270,27 @@ int main(int argc, char *argv[]) } /* Open Share Memory created by the model. */ - if ((OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME)) != EOK) { + ret = OpalOpenAsyncMem(ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME); + if (ret != EOK) { OpalPrint("%s: ERROR: Model shared memory not available\n", PROGNAME); exit(EXIT_FAILURE); } - /* For Redhawk, Assign this process to CPU 0 in order to support partial XHP */ AssignProcToCpu0(); /* Get IP Controler Parameters (ie: ip address, port number...) and * initialize the device on the QNX node. */ memset(&IconCtrlStruct, 0, sizeof(IconCtrlStruct)); - if ((err = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct))) != EOK) { - OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, err); + + ret = OpalGetAsyncCtrlParameters(&IconCtrlStruct, sizeof(IconCtrlStruct)); + if (ret != EOK) { + OpalPrint("%s: ERROR: Could not get controller parameters (%d).\n", PROGNAME, ret); exit(EXIT_FAILURE); } /* Initialize socket */ - if (InitSocket(IconCtrlStruct) != EOK) { + ret = InitSocket(IconCtrlStruct); + if (ret != EOK) { OpalPrint("%s: ERROR: Initialization failed.\n", PROGNAME); exit(EXIT_FAILURE); } @@ -326,16 +323,22 @@ int main(int argc, char *argv[]) #endif /* _DEBUG */ /* Start send/receive threads */ - if ((pthread_create(&tid_send, NULL, SendToIPPort, NULL)) == -1) + ret = pthread_create(&tid_send, NULL, SendToIPPort, NULL); + if (ret == -1) OpalPrint("%s: ERROR: Could not create thread (SendToIPPort), errno %d\n", PROGNAME, errno); - if ((pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL)) == -1) + + ret = pthread_create(&tid_recv, NULL, RecvFromIPPort, NULL); + if (ret == -1) OpalPrint("%s: ERROR: Could not create thread (RecvFromIPPort), errno %d\n", PROGNAME, errno); /* Wait for both threads to finish */ - if ((err = pthread_join(tid_send, NULL)) != 0) - OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, err); - if ((err = pthread_join(tid_recv, NULL)) != 0) - OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, err); + ret = pthread_join(tid_send, NULL); + if (ret != 0) + OpalPrint("%s: ERROR: pthread_join (SendToIPPort), errno %d\n", PROGNAME, ret); + + ret = pthread_join(tid_recv, NULL); + if (ret != 0) + OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, ret); /* Close the ip port and shared memories */ CloseSocket(IconCtrlStruct); diff --git a/clients/opal/udp/models/send_receive/src/socket.c b/clients/opal/udp/models/send_receive/src/socket.c index 298404a51..f49cc022b 100644 --- a/clients/opal/udp/models/send_receive/src/socket.c +++ b/clients/opal/udp/models/send_receive/src/socket.c @@ -2,8 +2,7 @@ * * Code example of an asynchronous program. This program is started * by the asynchronous controller and demonstrates how to send and - * receive data to and from the asynchronous icons and a UDP or TCP - * port. + * receive data to and from the asynchronous icons and a UDP port. * * @author Steffen Vogel * @author Mathieu Dubé-Dallaire @@ -35,43 +34,27 @@ struct sockaddr_in send_ad; /* Send address */ struct sockaddr_in recv_ad; /* Receive address */ int sd = -1; /* socket descriptor */ -int proto = UDP_PROTOCOL; int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) { struct ip_mreq mreq; /* Multicast group structure */ - int socket_type; - int socket_proto; - unsigned char TTL = 1; - unsigned char LOOP = 0; - int rc; + unsigned char TTL = 1, LOOP = 0; + int rc, proto, ret; proto = (int) IconCtrlStruct.FloatParam[0]; - OpalPrint("%s: Version : %s\n", PROGNAME, VERSION); - - switch (proto) { - case UDP_PROTOCOL: /* Communication using UDP/IP protocol */ - socket_proto = IPPROTO_UDP; - socket_type = SOCK_DGRAM; - OpalPrint("%s: Protocol : UDP/IP\n", PROGNAME); - break; - - case TCP_PROTOCOL: /* Communication using TCP/IP protocol */ - socket_proto = IPPROTO_IP; - socket_type = SOCK_STREAM; - OpalPrint("%s: Protocol : TCP/IP\n", PROGNAME); - break; - - default: /* Protocol is not recognized */ - OpalPrint("%s: ERROR: Protocol (%d) not supported!\n", PROGNAME, proto); - return EINVAL; + if (proto != UDP_PROTOCOL) { + OpalPrint("%s: This version of %s only supports UDP\n", PROGNAME, PROGNAME); + return EIO; } - + + + OpalPrint("%s: Version : %s\n", PROGNAME, VERSION); OpalPrint("%s: Remote Address : %s\n", PROGNAME, IconCtrlStruct.StringParam[0]); OpalPrint("%s: Remote Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[1]); /* Initialize the socket */ - if ((sd = socket(AF_INET, socket_type, socket_proto)) < 0) { + sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sd < 0) { OpalPrint("%s: ERROR: Could not open socket\n", PROGNAME); return EIO; } @@ -89,89 +72,82 @@ int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) recv_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[2]); /* Bind local port and address to socket. */ - if (bind(sd, (struct sockaddr *) &recv_ad, sizeof(struct sockaddr_in)) == -1) { + ret = bind(sd, (struct sockaddr *) &recv_ad, sizeof(struct sockaddr_in)); + if (ret == -1) { OpalPrint("%s: ERROR: Could not bind local port to socket\n", PROGNAME); return EIO; } else OpalPrint("%s: Local Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[2]); - switch (proto) { - case UDP_PROTOCOL: /* Communication using UDP/IP protocol */ - /* If sending to a multicast address */ - if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) { - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL)) == -1) { - OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n", PROGNAME, errno); - return EIO; - } - if (setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP)) == -1) { - OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n", PROGNAME, errno); - return EIO; - } + /* If sending to a multicast address */ + if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) { + ret = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL)); + if (ret == -1) { + OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n", PROGNAME, errno); + return EIO; + } + + ret = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP)); + if (ret == -1) { + OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n", PROGNAME, errno); + return EIO; + } - OpalPrint("%s: Configured socket for sending to multicast address\n", PROGNAME); - } + OpalPrint("%s: Configured socket for sending to multicast address\n", PROGNAME); + } - /* If receiving from a multicast group, register for it. */ - if (inet_addr(IconCtrlStruct.StringParam[1]) > 0) { - if ((inet_addr(IconCtrlStruct.StringParam[1]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) { - mreq.imr_multiaddr.s_addr = inet_addr(IconCtrlStruct.StringParam[1]); - mreq.imr_interface.s_addr = INADDR_ANY; + /* If receiving from a multicast group, register for it. */ + if (inet_addr(IconCtrlStruct.StringParam[1]) > 0) { + if ((inet_addr(IconCtrlStruct.StringParam[1]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) { + mreq.imr_multiaddr.s_addr = inet_addr(IconCtrlStruct.StringParam[1]); + mreq.imr_interface.s_addr = INADDR_ANY; - /* Have the multicast socket join the multicast group */ - if (setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)) == -1) { - OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME, errno); - return EIO; - } - - OpalPrint("%s: Added process to multicast group (%s)\n", - PROGNAME, IconCtrlStruct.StringParam[1]); - } - else { - OpalPrint("%s: WARNING: IP address for multicast group is not in multicast range. Ignored\n", - PROGNAME); - } - } - break; - - case TCP_PROTOCOL: /* Communication using TCP/IP protocol */ - OpalPrint("%s: Calling connect()\n", PROGNAME); - - /* Connect to server to start data transmission */ - rc = connect(sd, (struct sockaddr *) &send_ad, sizeof(send_ad)); - if (rc < 0) { - OpalPrint("%s: ERROR: Call to connect() failed\n", PROGNAME); + /* Have the multicast socket join the multicast group */ + ret = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); + if (ret == -1) { + OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME, errno); return EIO; } - break; + + OpalPrint("%s: Added process to multicast group (%s)\n", + PROGNAME, IconCtrlStruct.StringParam[1]); + } + else { + OpalPrint("%s: WARNING: IP address for multicast group is not in multicast range. Ignored\n", + PROGNAME); + } } return EOK; } +int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) +{ + if (sd < 0) { + shutdown(sd, SHUT_RDWR); + close(sd); + } + + return 0; +} + int SendPacket(char* DataSend, int datalength) { - int err; - - if(sd < 0) + if (sd < 0) return -1; /* Send the packet */ - if (proto == TCP_PROTOCOL) - err = send(sd, DataSend, datalength, 0); - else - err = sendto(sd, DataSend, datalength, 0, (struct sockaddr *)&send_ad, sizeof(send_ad)); - - return err; + return sendto(sd, DataSend, datalength, 0, (struct sockaddr *)&send_ad, sizeof(send_ad)); } int RecvPacket(char* DataRecv, int datalength, double timeout) { - int len; + int len, ret; struct sockaddr_in client_ad; + struct timeval tv; socklen_t client_ad_size = sizeof(client_ad); fd_set sd_set; - struct timeval tv; if (sd < 0) return -1; @@ -188,7 +164,8 @@ int RecvPacket(char* DataRecv, int datalength, double timeout) * necessary when reseting the model so we don't wait indefinitely * and prevent the process from exiting and freeing the port for * a future instance (model load). */ - switch (select(sd+1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv)) { + ret = select(sd+1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv); + switch (ret) { case -1: /* Error */ return -1; case 0: /* We hit the timeout */ @@ -206,20 +183,5 @@ int RecvPacket(char* DataRecv, int datalength, double timeout) memset(DataRecv, 0, datalength); /* Perform the reception */ - if (proto == TCP_PROTOCOL) - len = recv(sd, DataRecv, datalength, 0); - else - len = recvfrom(sd, DataRecv, datalength, 0, (struct sockaddr *) &client_ad, &client_ad_size); - - return len; -} - -int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) -{ - if (sd < 0) { - shutdown(sd, SHUT_RDWR); - close(sd); - } - - return 0; -} + return recvfrom(sd, DataRecv, datalength, 0, (struct sockaddr *) &client_ad, &client_ad_size); +} \ No newline at end of file diff --git a/clients/opal/udp/models/send_receive/src/utils.c b/clients/opal/udp/models/send_receive/src/utils.c index e8c599807..7a8e0ded3 100644 --- a/clients/opal/udp/models/send_receive/src/utils.c +++ b/clients/opal/udp/models/send_receive/src/utils.c @@ -18,57 +18,30 @@ #include "utils.h" #if defined(__QNXNTO__) -# include -# include -# include -# include + #include + #include + #include + #include #elif defined(__linux__) -# define _GNU_SOURCE 1 -# include -# if defined(__redhawk__) -# include -# include -# endif + #define _GNU_SOURCE 1 + #include #endif int AssignProcToCpu0(void) { -#if defined(__linux__) - #if defined(__redhawk__) - int rc; - pid_t pid = getpid(); - cpuset_t *pCpuset; - - pCpuset = cpuset_alloc(); - if (NULL == pCpuset) { - OpalPrint("Error allocating a cpuset\n"); - return ENOMEM; - } - - cpuset_init(pCpuset); - cpuset_set_cpu(pCpuset, 0, 1); - - rc = mpadvise(MPA_PRC_SETBIAS, MPA_TID, pid, pCpuset); - if (MPA_FAILURE == rc) { - rc = errno; - OpalPrint("Error from mpadvise, %d %s, for pid %d\n", errno, strerror(errno), pid); - cpuset_free(pCpuset); - return rc; - } - - cpuset_free(pCpuset); - #else +#ifdef __linux__ + int ret; cpu_set_t bindSet; CPU_ZERO(&bindSet); CPU_SET(0, &bindSet); - /* changing process cpu affinity */ - if (sched_setaffinity(0, sizeof(cpu_set_t), &bindSet) != 0) { + /* Changing process cpu affinity */ + ret = sched_setaffinity(0, sizeof(cpu_set_t), &bindSet); + if (ret != 0) { OpalPrint("Unable to bind the process to CPU 0. (sched_setaffinity errno %d)\n", errno); return EINVAL; } - - #endif + return EOK; #endif /* __linux__ */ } From 009a6b8a3afc154f4b87d0a3047834ade3418a81 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 11:33:26 +0200 Subject: [PATCH 06/16] updated copyright headers of AsyncIP code --- .../opal/udp/models/send_receive/include/config.h | 8 ++++---- .../opal/udp/models/send_receive/include/socket.h | 15 ++++----------- .../opal/udp/models/send_receive/include/utils.h | 2 +- clients/opal/udp/models/send_receive/src/main.c | 15 ++++----------- clients/opal/udp/models/send_receive/src/socket.c | 13 +++---------- clients/opal/udp/models/send_receive/src/utils.c | 3 +-- 6 files changed, 17 insertions(+), 39 deletions(-) diff --git a/clients/opal/udp/models/send_receive/include/config.h b/clients/opal/udp/models/send_receive/include/config.h index cbf09b8af..3495d67f1 100644 --- a/clients/opal/udp/models/send_receive/include/config.h +++ b/clients/opal/udp/models/send_receive/include/config.h @@ -1,9 +1,9 @@ -/** Compiled-in settings +/** Compile-time configuration. * - * @author Steffen Vogel - * @copyright 2014, Institute for Automation of Complex Power Systems, EONERC * @file - */ + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ #ifndef _CONFIG_H_ #define _CONFIG_H_ diff --git a/clients/opal/udp/models/send_receive/include/socket.h b/clients/opal/udp/models/send_receive/include/socket.h index 336e18eb2..ccc2c7718 100644 --- a/clients/opal/udp/models/send_receive/include/socket.h +++ b/clients/opal/udp/models/send_receive/include/socket.h @@ -1,16 +1,9 @@ -/** Helper functions for socket +/** Helper functions for sockets. * - * Code example of an asynchronous program. This program is started - * by the asynchronous controller and demonstrates how to send and - * receive data to and from the asynchronous icons and a UDP or TCP - * port. - * - * @author Steffen Vogel - * @author Mathieu Dubé-Dallaire - * @copyright 2014, Institute for Automation of Complex Power Systems, EONERC - * @copyright 2003, OPAL-RT Technologies inc * @file - */ + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ #ifndef _SOCKET_H_ #define _SOCKET_H_ diff --git a/clients/opal/udp/models/send_receive/include/utils.h b/clients/opal/udp/models/send_receive/include/utils.h index f1c387d50..61a094f1a 100644 --- a/clients/opal/udp/models/send_receive/include/utils.h +++ b/clients/opal/udp/models/send_receive/include/utils.h @@ -1,4 +1,4 @@ -/** Configure Scheduler +/** Configure scheduler. * * @file * @author Steffen Vogel diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 2ecd769e3..273b5a5ff 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -1,16 +1,9 @@ -/** Main +/** Main routine of AsyncIP. * - * Code example of an asynchronous program. This program is started - * by the asynchronous controller and demonstrates how to send and - * receive data to and from the asynchronous icons and a UDP or TCP - * port. - * - * @author Steffen Vogel - * @author Mathieu Dubé-Dallaire - * @copyright 2014, Institute for Automation of Complex Power Systems, EONERC - * @copyright 2003, OPAL-RT Technologies inc * @file - */ + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ /* Standard ANSI C headers needed for this program */ #include diff --git a/clients/opal/udp/models/send_receive/src/socket.c b/clients/opal/udp/models/send_receive/src/socket.c index f49cc022b..842f78056 100644 --- a/clients/opal/udp/models/send_receive/src/socket.c +++ b/clients/opal/udp/models/send_receive/src/socket.c @@ -1,15 +1,8 @@ -/** Helper functions for socket - * - * Code example of an asynchronous program. This program is started - * by the asynchronous controller and demonstrates how to send and - * receive data to and from the asynchronous icons and a UDP port. +/** Helper functions for sockets. * * @author Steffen Vogel - * @author Mathieu Dubé-Dallaire - * @copyright 2014, Institute for Automation of Complex Power Systems, EONERC - * @copyright 2003, OPAL-RT Technologies inc - * @file - */ + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ #include #include diff --git a/clients/opal/udp/models/send_receive/src/utils.c b/clients/opal/udp/models/send_receive/src/utils.c index 7a8e0ded3..192661dfc 100644 --- a/clients/opal/udp/models/send_receive/src/utils.c +++ b/clients/opal/udp/models/send_receive/src/utils.c @@ -1,6 +1,5 @@ -/** Configure Scheduler +/** Configure scheduler. * - * @file * @author Steffen Vogel * @author Mathieu Dubé-Dallaire * @copyright 2003, OPAL-RT Technologies inc From ecd996f251ea4fa707cb92768b8b557acb8d1fbc Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 11:34:46 +0200 Subject: [PATCH 07/16] asyncip: we only support RedHat linux --- .../udp/models/send_receive/include/socket.h | 1 - .../udp/models/send_receive/include/utils.h | 2 -- .../opal/udp/models/send_receive/src/main.c | 15 ++------------ .../opal/udp/models/send_receive/src/utils.c | 20 +++++-------------- 4 files changed, 7 insertions(+), 31 deletions(-) diff --git a/clients/opal/udp/models/send_receive/include/socket.h b/clients/opal/udp/models/send_receive/include/socket.h index ccc2c7718..a33cf6686 100644 --- a/clients/opal/udp/models/send_receive/include/socket.h +++ b/clients/opal/udp/models/send_receive/include/socket.h @@ -13,7 +13,6 @@ #define UDP_PROTOCOL 1 #define TCP_PROTOCOL 2 -#define EOK 0 int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct); diff --git a/clients/opal/udp/models/send_receive/include/utils.h b/clients/opal/udp/models/send_receive/include/utils.h index 61a094f1a..762aca20a 100644 --- a/clients/opal/udp/models/send_receive/include/utils.h +++ b/clients/opal/udp/models/send_receive/include/utils.h @@ -10,8 +10,6 @@ #ifndef _UTILS_H_ #define _UTILS_H_ -#define EOK 0 - int AssignProcToCpu0(void); #endif /* _UTILS_H_ */ diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 273b5a5ff..20470dd90 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -6,28 +6,17 @@ *********************************************************************************/ /* Standard ANSI C headers needed for this program */ -#include -#include #include #include #include +#include +#include #include -#include -#include #include #include #include #include -#if defined(__QNXNTO__) - #include - #include - #include -#elif defined(__linux__) - #define _GNU_SOURCE 1 - #include -#endif - /* Define RTLAB before including OpalPrint.h for messages to be sent * to the OpalDisplay. Otherwise stdout will be used. */ #define RTLAB diff --git a/clients/opal/udp/models/send_receive/src/utils.c b/clients/opal/udp/models/send_receive/src/utils.c index 192661dfc..23778e008 100644 --- a/clients/opal/udp/models/send_receive/src/utils.c +++ b/clients/opal/udp/models/send_receive/src/utils.c @@ -7,6 +7,7 @@ *********************************************************************************/ #include +#include /* Define RTLAB before including OpalPrint.h for messages to be sent * to the OpalDisplay. Otherwise stdout will be used. */ @@ -16,31 +17,20 @@ #include "config.h" #include "utils.h" -#if defined(__QNXNTO__) - #include - #include - #include - #include -#elif defined(__linux__) - #define _GNU_SOURCE 1 - #include -#endif - int AssignProcToCpu0(void) { -#ifdef __linux__ int ret; cpu_set_t bindSet; + CPU_ZERO(&bindSet); CPU_SET(0, &bindSet); /* Changing process cpu affinity */ ret = sched_setaffinity(0, sizeof(cpu_set_t), &bindSet); - if (ret != 0) { - OpalPrint("Unable to bind the process to CPU 0. (sched_setaffinity errno %d)\n", errno); + if (ret) { + OpalPrint("Unable to bind the process to CPU 0: %d\n", errno); return EINVAL; } - return EOK; -#endif /* __linux__ */ + return 0; } From d0a1022e4844dafbf6b291b764d7f1465fe3bf2a Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 11:36:34 +0200 Subject: [PATCH 08/16] asyncip: refactored socket code to eliminate global variables --- .../udp/models/send_receive/include/socket.h | 16 +++-- .../opal/udp/models/send_receive/src/main.c | 13 ++-- .../opal/udp/models/send_receive/src/socket.c | 68 +++++++++---------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/clients/opal/udp/models/send_receive/include/socket.h b/clients/opal/udp/models/send_receive/include/socket.h index a33cf6686..1fd588bed 100644 --- a/clients/opal/udp/models/send_receive/include/socket.h +++ b/clients/opal/udp/models/send_receive/include/socket.h @@ -8,18 +8,26 @@ #ifndef _SOCKET_H_ #define _SOCKET_H_ +#include + #define RT #include "OpalGenAsyncParamCtrl.h" #define UDP_PROTOCOL 1 #define TCP_PROTOCOL 2 -int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct); +struct socket { + struct sockaddr_in send_ad; /* Send address */ + struct sockaddr_in recv_ad; /* Receive address */ + int sd; /* socket descriptor */ +}; -int SendPacket(char* DataSend, int datalength); +int socket_init(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct); -int RecvPacket(char* DataRecv, int datalength, double timeout); +int socket_send(struct socket *s, char *data, int len); -int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct); +int socket_recv(struct socket *s, char *data, int len, double timeout); + +int socket_close(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct); #endif /* _SOCKET_H_ */ diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 20470dd90..51d4840e3 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -59,6 +59,8 @@ void Tick(int sig, siginfo_t *si, void *ptr) PROGNAME, (CpuTime - CpuTimeStart) / CPU_TICKS, ModelTime, msg_send->sequence, msg_send->data[0].f); } #endif /* _DEBUG */ +/* Global Variables */ +struct socket skt; static void * SendToIPPort(void *arg) { @@ -128,7 +130,7 @@ static void * SendToIPPort(void *arg) msg_hton(msg); /* Perform the actual write to the ip port */ - ret = SendPacket((char *) msg, MSG_LEN(msg->length)); + ret = socket_send(&skt, (char *) msg, len); if (ret < 0) OpalSetAsyncSendIconError(errno, SendID); else @@ -175,8 +177,8 @@ static void * RecvFromIPPort(void *arg) do { /* Receive message */ - n = RecvPacket((char *) msg, sizeof(buf), 1.0); - if (n < 1) { + ret = socket_recv(&skt, (char *) msg, sizeof(buf), 1.0); + if (ret < 1) { ModelState = OpalGetAsyncModelState(); if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { if (n == 0) /* timeout, so we continue silently */ @@ -271,7 +273,7 @@ int main(int argc, char *argv[]) } /* Initialize socket */ - ret = InitSocket(IconCtrlStruct); + ret = socket_init(&skt, IconCtrlStruct); if (ret != EOK) { OpalPrint("%s: ERROR: Initialization failed.\n", PROGNAME); exit(EXIT_FAILURE); @@ -323,7 +325,8 @@ int main(int argc, char *argv[]) OpalPrint("%s: ERROR: pthread_join (RecvFromIPPort), errno %d\n", PROGNAME, ret); /* Close the ip port and shared memories */ - CloseSocket(IconCtrlStruct); + socket_close(&skt, IconCtrlStruct); + OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME); OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME); diff --git a/clients/opal/udp/models/send_receive/src/socket.c b/clients/opal/udp/models/send_receive/src/socket.c index 842f78056..a7f5cad76 100644 --- a/clients/opal/udp/models/send_receive/src/socket.c +++ b/clients/opal/udp/models/send_receive/src/socket.c @@ -11,7 +11,6 @@ #include #include #include -#include #include /* Define RTLAB before including OpalPrint.h for messages to be sent @@ -23,12 +22,7 @@ #include "config.h" #include "socket.h" -/* Globals variables */ -struct sockaddr_in send_ad; /* Send address */ -struct sockaddr_in recv_ad; /* Receive address */ -int sd = -1; /* socket descriptor */ - -int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) +int socket_init(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct) { struct ip_mreq mreq; /* Multicast group structure */ unsigned char TTL = 1, LOOP = 0; @@ -46,26 +40,26 @@ int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) OpalPrint("%s: Remote Port : %d\n", PROGNAME, (int) IconCtrlStruct.FloatParam[1]); /* Initialize the socket */ - sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (sd < 0) { + s->sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (s->sd < 0) { OpalPrint("%s: ERROR: Could not open socket\n", PROGNAME); return EIO; } /* Set the structure for the remote port and address */ - memset(&send_ad, 0, sizeof(send_ad)); - send_ad.sin_family = AF_INET; - send_ad.sin_addr.s_addr = inet_addr(IconCtrlStruct.StringParam[0]); - send_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[1]); + memset(&s->send_ad, 0, sizeof(s->send_ad)); + s->send_ad.sin_family = AF_INET; + s->send_ad.sin_addr.s_addr = inet_addr(IconCtrlStruct.StringParam[0]); + s->send_ad.sin_port = htons((u_short) IconCtrlStruct.FloatParam[1]); /* Set the structure for the local port and address */ - memset(&recv_ad, 0, sizeof(recv_ad)); - recv_ad.sin_family = AF_INET; - recv_ad.sin_addr.s_addr = INADDR_ANY; - recv_ad.sin_port = htons((u_short)IconCtrlStruct.FloatParam[2]); + memset(&s->recv_ad, 0, sizeof(s->recv_ad)); + s->recv_ad.sin_family = AF_INET; + s->recv_ad.sin_addr.s_addr = INADDR_ANY; + s->recv_ad.sin_port = htons((u_short) IconCtrlStruct.FloatParam[2]); /* Bind local port and address to socket. */ - ret = bind(sd, (struct sockaddr *) &recv_ad, sizeof(struct sockaddr_in)); + ret = bind(s->sd, (struct sockaddr *) &s->recv_ad, sizeof(struct sockaddr_in)); if (ret == -1) { OpalPrint("%s: ERROR: Could not bind local port to socket\n", PROGNAME); return EIO; @@ -75,13 +69,13 @@ int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) /* If sending to a multicast address */ if ((inet_addr(IconCtrlStruct.StringParam[0]) & inet_addr("240.0.0.0")) == inet_addr("224.0.0.0")) { - ret = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL)); + ret = setsockopt(s->sd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL)); if (ret == -1) { OpalPrint("%s: ERROR: Could not set TTL for multicast send (%d)\n", PROGNAME, errno); return EIO; } - ret = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP)); + ret = setsockopt(s->sd, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&LOOP, sizeof(LOOP)); if (ret == -1) { OpalPrint("%s: ERROR: Could not set loopback for multicast send (%d)\n", PROGNAME, errno); return EIO; @@ -97,7 +91,7 @@ int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) mreq.imr_interface.s_addr = INADDR_ANY; /* Have the multicast socket join the multicast group */ - ret = setsockopt(sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); + ret = setsockopt(s->sd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mreq, sizeof(mreq)); if (ret == -1) { OpalPrint("%s: ERROR: Could not join multicast group (%d)\n", PROGNAME, errno); return EIO; @@ -115,39 +109,39 @@ int InitSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) return EOK; } -int CloseSocket(Opal_GenAsyncParam_Ctrl IconCtrlStruct) +int socket_close(struct socket *s, Opal_GenAsyncParam_Ctrl IconCtrlStruct) { - if (sd < 0) { - shutdown(sd, SHUT_RDWR); - close(sd); + if (s->sd < 0) { + shutdown(s->sd, SHUT_RDWR); + close(s->sd); } return 0; } -int SendPacket(char* DataSend, int datalength) +int socket_send(struct socket *s, char *data, int len) { - if (sd < 0) + if (s->sd < 0) return -1; /* Send the packet */ - return sendto(sd, DataSend, datalength, 0, (struct sockaddr *)&send_ad, sizeof(send_ad)); + return sendto(s->sd, data, len, 0, (struct sockaddr *) &s->send_ad, sizeof(s->send_ad)); } -int RecvPacket(char* DataRecv, int datalength, double timeout) +int socket_recv(struct socket *s, char *data, int len, double timeout) { - int len, ret; + int ret; struct sockaddr_in client_ad; struct timeval tv; socklen_t client_ad_size = sizeof(client_ad); fd_set sd_set; - if (sd < 0) + if (s->sd < 0) return -1; /* Set the descriptor set for the select() call */ FD_ZERO(&sd_set); - FD_SET(sd, &sd_set); + FD_SET(s->sd, &sd_set); /* Set the tv structure to the correct timeout value */ tv.tv_sec = (int) timeout; @@ -157,14 +151,14 @@ int RecvPacket(char* DataRecv, int datalength, double timeout) * necessary when reseting the model so we don't wait indefinitely * and prevent the process from exiting and freeing the port for * a future instance (model load). */ - ret = select(sd+1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv); + ret = select(s->sd + 1, &sd_set, (fd_set *) 0, (fd_set *) 0, &tv); switch (ret) { case -1: /* Error */ return -1; case 0: /* We hit the timeout */ return 0; default: - if (!(FD_ISSET(sd, &sd_set))) { + if (!(FD_ISSET(s->sd, &sd_set))) { /* We received something, but it's not on "sd". Since sd is the only * descriptor in the set... */ OpalPrint("%s: RecvPacket: God, is that You trying to reach me?\n", PROGNAME); @@ -172,9 +166,9 @@ int RecvPacket(char* DataRecv, int datalength, double timeout) } } - /* Clear the DataRecv array (in case we receive an incomplete packet) */ - memset(DataRecv, 0, datalength); + /* Clear the data array (in case we receive an incomplete packet) */ + memset(data, 0, len); /* Perform the reception */ - return recvfrom(sd, DataRecv, datalength, 0, (struct sockaddr *) &client_ad, &client_ad_size); + return recvfrom(s->sd, data, len, 0, (struct sockaddr *) &client_ad, &client_ad_size); } \ No newline at end of file From 565c6fb0941a384673fe963aa22560332728063a Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 12:06:31 +0200 Subject: [PATCH 09/16] asyncip: removed debugging feature --- .../opal/udp/models/send_receive/src/main.c | 58 ------------------- 1 file changed, 58 deletions(-) diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 51d4840e3..22a2f6e47 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -36,29 +36,6 @@ #define ASYNC_SHMEM_SIZE atoi(argv[2]) #define PRINT_SHMEM_NAME argv[3] -#ifdef _DEBUG // TODO: workaround - -#define CPU_TICKS 3466948000 -struct msg *msg_send = NULL; - -void Tick(int sig, siginfo_t *si, void *ptr) -{ - Opal_GenAsyncParam_Ctrl *IconCtrlStruct; - unsigned long long CpuTime, CpuTimeStart; - double ModelTime; - - if (!msg_send) - return; - - IconCtrlStruct = (Opal_GenAsyncParam_Ctrl*) si->si_value.sival_ptr; - - OpalGetAsyncStartExecCpuTime(IconCtrlStruct, &CpuTimeStart); - OpalGetAsyncModelTime(IconCtrlStruct, &CpuTime, &ModelTime); - - OpalPrint("%s: CpuTime: %llu\tModelTime: %.3f\tSequence: %hu\tValue: %.2f\n", - PROGNAME, (CpuTime - CpuTimeStart) / CPU_TICKS, ModelTime, msg_send->sequence, msg_send->data[0].f); -} -#endif /* _DEBUG */ /* Global Variables */ struct socket skt; @@ -76,10 +53,6 @@ static void * SendToIPPort(void *arg) char buf[MSG_LEN(MAX_VALUES)]; struct msg *msg = (struct msg *) buf; -#ifdef _DEBUG // TODO: workaround - msg_send = msg; -#endif /* _DEBUG */ - OpalPrint("%s: SendToIPPort thread started\n", PROGNAME); OpalGetNbAsyncSendIcon(&nbSend); @@ -279,33 +252,6 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } -#ifdef _DEBUG - /* Setup signals */ - struct sigaction sa_tick = { - .sa_flags = SA_SIGINFO, - .sa_sigaction = Tick - }; - - sigemptyset(&sa_tick.sa_mask); - sigaction(SIGUSR1, &sa_tick, NULL); - - /* Setup timer */ - timer_t t; - struct sigevent sev = { - .sigev_notify = SIGEV_SIGNAL, - .sigev_signo = SIGUSR1, - .sigev_value.sival_ptr = &IconCtrlStruct - }; - - struct itimerspec its = { - .it_interval = { 1, 0 }, - .it_value = { 0, 1 } - }; - - timer_create(CLOCK_REALTIME, &sev, &t); - timer_settime(t, 0, &its, NULL); -#endif /* _DEBUG */ - /* Start send/receive threads */ ret = pthread_create(&tid_send, NULL, SendToIPPort, NULL); if (ret == -1) @@ -330,9 +276,5 @@ int main(int argc, char *argv[]) OpalCloseAsyncMem (ASYNC_SHMEM_SIZE, ASYNC_SHMEM_NAME); OpalSystemCtrl_UnRegister(PRINT_SHMEM_NAME); -#ifdef _DEBUG - timer_delete(t); -#endif /* _DEBUG */ - return 0; } From 46d0d4cc84937c72cb598531293e014df0191c1d Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 11:38:05 +0200 Subject: [PATCH 10/16] asyncip: support compilation with GCC / clang --- clients/Makefile.inc | 19 +++++ .../opal/udp/models/send_receive/Makefile.mk | 57 +++++++++++++ .../opal/udp/models/send_receive/src/compat.c | 30 +++++++ .../opal/udp/models/send_receive/villas.mk | 85 ------------------- 4 files changed, 106 insertions(+), 85 deletions(-) create mode 100644 clients/Makefile.inc create mode 100644 clients/opal/udp/models/send_receive/Makefile.mk create mode 100644 clients/opal/udp/models/send_receive/src/compat.c delete mode 100644 clients/opal/udp/models/send_receive/villas.mk diff --git a/clients/Makefile.inc b/clients/Makefile.inc new file mode 100644 index 000000000..1f067acde --- /dev/null +++ b/clients/Makefile.inc @@ -0,0 +1,19 @@ +ASYNCIP_PATH = $(SRCDIR)/clients/opal/udp/models/send_receive + +clients: clients-opal + +clients-opal: + $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk AsyncIP \ + RTLAB_INTEL_COMPILER=0 \ + PROTOCOL=GTNET_SKT \ + OPAL_LIBS="-lSystem -luuid" \ + OPAL_LIBPATH=-L$(SRCDIR)/thirdparty/libopal/ \ + OPAL_INCPATH=-I$(SRCDIR)/thirdparty/libopal/include/opal + +clean-clients: + $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk clean + +install-clients: + $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk install + +.PHONY: clients clean-clients install-clients \ No newline at end of file diff --git a/clients/opal/udp/models/send_receive/Makefile.mk b/clients/opal/udp/models/send_receive/Makefile.mk new file mode 100644 index 000000000..b56efb1d6 --- /dev/null +++ b/clients/opal/udp/models/send_receive/Makefile.mk @@ -0,0 +1,57 @@ +TARGET = AsyncIP + +VPATH = $(SRCDIR)/src + +RTLAB_INTEL_COMPILER ?= 1 + +# Compiler selection +ifeq ($(RTLAB_INTEL_COMPILER),1) + CC = opicc + LD = opicpc +else + CC = gcc + LD = g++ + + INTEL_LIBS = -limf -lirc + INTEL_OBJS = compat.o +endif + +# Support for debugging symbols +ifeq ($(DEBUG),1) + CC_DEBUG_OPTS = -g -D_DEBUG + LD_DEBUG_OPTS = -g +else + CC_DEBUG_OPTS = -O + LD_DEBUG_OPTS = +endif + +TARGET_LIB = -lpthread -lm -ldl -lutil -lrt $(INTEL_LIBS) + +INCLUDES = -I. $(OPAL_INCPATH) -Iinclude +LIBPATH = -L. $(OPAL_LIBPATH) +CC_OPTS = -m32 -std=c99 -D_GNU_SOURCE -MMD +LD_OPTS = -m32 +OBJS = main.o msg.o utils.o socket.o $(INTEL_OBJS) + +ifneq ($(PROTOCOL),) + CC_OPTS += -DPROTOCOL=$(PROTOCOL) +endif + +ADDLIB = -lOpalCore -lOpalUtils +LIBS = -lOpalAsyncApiCore $(ADDLIB) $(TARGET_LIB) $(OPAL_LIBS) + +CFLAGS = -c $(CC_OPTS) $(CC_DEBUG_OPTS) $(INCLUDES) +LDFLAGS = $(LD_OPTS) $(LD_DEBUG_OPTS) $(LIBPATH) + +all: $(TARGET) + +install: $(TARGET) + install -m 0755 -D -t $(DESTDIR)$(PREFIX)/bin $(TARGET) + +clean: + rm -f $(OBJS) $(TARGET) + +$(TARGET): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +-include $(wildcard *.d) \ No newline at end of file diff --git a/clients/opal/udp/models/send_receive/src/compat.c b/clients/opal/udp/models/send_receive/src/compat.c new file mode 100644 index 000000000..e075e08bb --- /dev/null +++ b/clients/opal/udp/models/send_receive/src/compat.c @@ -0,0 +1,30 @@ +/** Compatibility code for GCC + * + * OPAL-RT's libSystem.a links against some Intel + * + * @file + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ + +#include + +size_t __intel_sse2_strlen(const char *s) +{ + return strlen(s); +} + +void * _intel_fast_memset(void *b, int c, size_t len) +{ + return memset(b, c, len); +} + +void * _intel_fast_memcpy(void *restrict dst, const void *restrict src, size_t n) +{ + return memcpy(dst, src, n); +} + +int _intel_fast_memcmp(const void *s1, const void *s2, size_t n) +{ + return memcmp(s1, s2, n); +} diff --git a/clients/opal/udp/models/send_receive/villas.mk b/clients/opal/udp/models/send_receive/villas.mk deleted file mode 100644 index 1e384d1be..000000000 --- a/clients/opal/udp/models/send_receive/villas.mk +++ /dev/null @@ -1,85 +0,0 @@ -# ----------------------------------------------------------------------------# -# Specify program name -PROGRAM = s2ss - -# ----------------------------------------------------------------------------# -# Specify default values if we are not compiling from RT-LAB -# -# ----------------------------------------------------------------------------# -TARGET_OPALRT_ROOT = /usr/opalrt - -# ----------------------------------------------------------------------------# -# QNX v6.x -# -ifeq "$(SYSNAME)" "nto" - CC = gcc - LD = $(CC) - TARGET_LIB = -lsocket -endif -# ----------------------------------------------------------------------------# - -# ----------------------------------------------------------------------------# -# RedHawk Linux -# -ifeq "$(shell uname)" "Linux" - RTLAB_INTEL_COMPILER ?= 1 - - # Intel Compiler support - ifeq ($(RTLAB_INTEL_COMPILER),1) - CC = opicc - LD = opicpc - # Gnu Compiler support - else - CC = gcc - LD = g++ - INTEL_LIBS = -limf -lirc - endif - - # RedHat or RedHawk - LINUX_FLAVOR = $(shell uname -r | grep RedHawk) - ifneq "$(LINUX_FLAVOR) " " " ### Linux (RedHat) - RH_FLAGS = -D_GNU_SOURCE -D__redhawk__ - RH_LIBS = -lccur_rt - else - RH_FLAGS = -D_GNU_SOURCE - endif - - TARGET_LIB = -lpthread -lm -ldl -lutil -lrt $(RH_LIBS) $(INTEL_LIBS) -endif -# ----------------------------------------------------------------------------# - -# Support for debugging symbols -ifeq ($(DEBUG),1) - CC_DEBUG_OPTS=-g -D_DEBUG - LD_DEBUG_OPTS=-g -else - CC_DEBUG_OPTS=-O - LD_DEBUG_OPTS= -endif - -INCLUDES = -I. -LIBPATH = -L. $(OPAL_LIBPATH) -CC_OPTS = -std=c99 -LD_OPTS = -OBJS = main.o msg.o utils.o socket.o - -ADDLIB = -lOpalCore -lOpalUtils -LIBS = -lOpalAsyncApiCore $(ADDLIB) $(TARGET_LIB) $(OPAL_LIBS) - -CFLAGS = -c $(CC_OPTS) $(CC_DEBUG_OPTS) $(RH_FLAGS) $(INCLUDES) -LDFLAGS = $(LD_OPTS) $(LD_DEBUG_OPTS) $(LIBPATH) - -all: $(PROGRAM) - -install: - \mkdir -p $(TARGET_OPALRT_ROOT)/local - \chmod 755 $(TARGET_OPALRT_ROOT)/local - \cp -f $(PROGRAM) $(TARGET_OPALRT_ROOT)/local - -clean: - \rm -f $(OBJS) $(PROGRAM) - -$(PROGRAM): $(OBJS) - $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) - chmod 777 $@ - @echo "### Created executable: $(PROGRAM)" From 77f6a7209fa0697cb39515e5f69324ee1e55f03d Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 12:08:11 +0200 Subject: [PATCH 11/16] asyncip: refactor for better coding style --- .../opal/udp/models/send_receive/src/main.c | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 22a2f6e47..71506a0e3 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -41,9 +41,8 @@ struct socket skt; static void * SendToIPPort(void *arg) { - unsigned int ModelState, SendID = 1, i, n; - int nbSend = 0, ret; - uint32_t seq = 0; + unsigned int ModelState, SendID = 1, Sequence = 0; + int nbSend = 0, ret, cnt, len; /* Data from OPAL-RT model */ double mdldata[MAX_VALUES]; @@ -63,12 +62,12 @@ static void * SendToIPPort(void *arg) do { /* This call unblocks when the 'Data Ready' line of a send icon is asserted. */ - n = OpalWaitForAsyncSendRequest(&SendID); - if (n != EOK) { + ret = OpalWaitForAsyncSendRequest(&SendID); + if (ret != EOK) { ModelState = OpalGetAsyncModelState(); if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { - OpalSetAsyncSendIconError(n, SendID); - OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, n); + OpalSetAsyncSendIconError(ret, SendID); + OpalPrint("%s: OpalWaitForAsyncSendRequest(), errno %d\n", PROGNAME, ret); } continue; @@ -93,13 +92,13 @@ static void * SendToIPPort(void *arg) clock_gettime(CLOCK_REALTIME, &now); msg->length = mdldata_size / sizeof(double); - for (i = 0; i < msg->length; i++) - msg->data[i].f = (float) mdldata[i]; - - msg->sequence = seq++; + msg->sequence = Sequence++; msg->ts.sec = now.tv_sec; msg->ts.nsec = now.tv_nsec; - + + for (int i = 0; i < msg->length; i++) + msg->data[i].f = (float) mdldata[i]; + msg_hton(msg); /* Perform the actual write to the ip port */ @@ -129,8 +128,8 @@ static void * SendToIPPort(void *arg) static void * RecvFromIPPort(void *arg) { - unsigned int ModelState, RecvID = 1, i, n; - int nbRecv = 0, ret; + unsigned int ModelState, RecvID = 1; + int nbRecv = 0, ret, cnt; /* Data from OPAL-RT model */ double mdldata[MAX_VALUES]; @@ -154,9 +153,9 @@ static void * RecvFromIPPort(void *arg) if (ret < 1) { ModelState = OpalGetAsyncModelState(); if ((ModelState != STATE_RESET) && (ModelState != STATE_STOP)) { - if (n == 0) /* timeout, so we continue silently */ + if (ret == 0) /* timeout, so we continue silently */ OpalPrint("%s: Timeout while waiting for data\n", PROGNAME, errno); - if (n == -1) /* a more serious error, so we print it */ + if (ret == -1) /* a more serious error, so we print it */ OpalPrint("%s: Error %d while waiting for data\n", PROGNAME, errno); continue; @@ -210,7 +209,6 @@ int main(int argc, char *argv[]) Opal_GenAsyncParam_Ctrl IconCtrlStruct; pthread_t tid_send, tid_recv; - pthread_attr_t attr_send, attr_recv; OpalPrint("%s: This is %s client version %s\n", PROGNAME, PROGNAME, VERSION); @@ -221,7 +219,8 @@ int main(int argc, char *argv[]) } /* Enable the OpalPrint function. This prints to the OpalDisplay. */ - if (OpalSystemCtrl_Register(PRINT_SHMEM_NAME) != EOK) { + ret = OpalSystemCtrl_Register(PRINT_SHMEM_NAME); + if (ret != EOK) { printf("%s: ERROR: OpalPrint() access not available\n", PROGNAME); exit(EXIT_FAILURE); } From 49263c4a701c39543dad88459c39e80b0745f94c Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 12:09:06 +0200 Subject: [PATCH 12/16] asyncip: add support for GTNET-SKT --- .../opal/udp/models/send_receive/.gitignore | 3 + .../udp/models/send_receive/include/config.h | 11 ++- .../opal/udp/models/send_receive/src/main.c | 77 ++++++++++++++----- 3 files changed, 69 insertions(+), 22 deletions(-) create mode 100644 clients/opal/udp/models/send_receive/.gitignore diff --git a/clients/opal/udp/models/send_receive/.gitignore b/clients/opal/udp/models/send_receive/.gitignore new file mode 100644 index 000000000..196fc2c48 --- /dev/null +++ b/clients/opal/udp/models/send_receive/.gitignore @@ -0,0 +1,3 @@ +*.o +*.d +AsyncIP diff --git a/clients/opal/udp/models/send_receive/include/config.h b/clients/opal/udp/models/send_receive/include/config.h index 3495d67f1..b95d618cb 100644 --- a/clients/opal/udp/models/send_receive/include/config.h +++ b/clients/opal/udp/models/send_receive/include/config.h @@ -9,8 +9,17 @@ #define _CONFIG_H_ #define PROGNAME "VILLASnode-OPAL-UDP" -#define VERSION "0.5" +#define VERSION "0.6" #define MAX_VALUES 64 +/* List of protocols */ +#define VILLAS 1 +#define GTNET_SKT 2 + +/* Default protocol */ +#ifndef PROTOCOL + #define PROTOCOL VILLAS +#endif + #endif /* _CONFIG_H_ */ \ No newline at end of file diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/udp/models/send_receive/src/main.c index 71506a0e3..24ec3a456 100644 --- a/clients/opal/udp/models/send_receive/src/main.c +++ b/clients/opal/udp/models/send_receive/src/main.c @@ -25,11 +25,14 @@ /* This is the message format */ #include "config.h" -#include "msg.h" -#include "msg_format.h" #include "socket.h" #include "utils.h" +#if PROTOCOL == VILLAS + #include "msg.h" + #include "msg_format.h" +#endif + /* 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 ASYNC_SHMEM_NAME argv[1] @@ -48,9 +51,13 @@ static void * SendToIPPort(void *arg) double mdldata[MAX_VALUES]; int mdldata_size; - /* Data from VILLASnode */ +#if PROTOCOL == VILLAS char buf[MSG_LEN(MAX_VALUES)]; struct msg *msg = (struct msg *) buf; +#elif PROTOCOL == GTNET_SKT + char buf[MAX_VALUES * sizeof(float)]; + float *msg = (float *) buf; +#endif OpalPrint("%s: SendToIPPort thread started\n", PROGNAME); @@ -78,7 +85,8 @@ static void * SendToIPPort(void *arg) /* Get the size of the data being sent by the unblocking SendID */ OpalGetAsyncSendIconDataLength(&mdldata_size, SendID); - if (mdldata_size / sizeof(double) > MAX_VALUES) { + cnt = mdldata_size / sizeof(double); + if (cnt > MAX_VALUES) { OpalPrint("%s: Number of signals for SendID=%d exceeds allowed maximum (%d)\n", PROGNAME, SendID, MAX_VALUES); return NULL; @@ -86,7 +94,8 @@ static void * SendToIPPort(void *arg) /* Read data from the model */ OpalGetAsyncSendIconData(mdldata, mdldata_size, SendID); - + +#if PROTOCOL == VILLAS /* Get current time */ struct timespec now; clock_gettime(CLOCK_REALTIME, &now); @@ -100,6 +109,16 @@ static void * SendToIPPort(void *arg) msg->data[i].f = (float) mdldata[i]; msg_hton(msg); + + len = MSG_LEN(msg->length); +#elif PROTOCOL == GTNET_SKT + for (int i = 0; i < cnt; i++) + msg[i] = (float) mdldata[i]; + + len = mdldata_size / sizeof(double) * sizeof(float); +#else + #error Unknown protocol +#endif /* Perform the actual write to the ip port */ ret = socket_send(&skt, (char *) msg, len); @@ -135,9 +154,15 @@ static void * RecvFromIPPort(void *arg) double mdldata[MAX_VALUES]; int mdldata_size; - /* Data from VILLASnode */ +#if PROTOCOL == VILLAS char buf[MSG_LEN(MAX_VALUES)]; struct msg *msg = (struct msg *) buf; +#elif PROTOCOL == GTNET_SKT + char buf[MAX_VALUES * sizeof(float)]; + float *msg = (float *) buf; +#else + #error Unknown protocol +#endif OpalPrint("%s: RecvFromIPPort thread started\n", PROGNAME); @@ -162,7 +187,17 @@ static void * RecvFromIPPort(void *arg) } break; } + + /* Get the number of signals to send back to the model */ + OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID); + cnt = mdldata_size / sizeof(double); + if (cnt > MAX_VALUES) { + OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n", + PROGNAME, RecvID, cnt, MAX_VALUES); + return NULL; + } +#if PROTOCOL == VILLAS msg_ntoh(msg); ret = msg_verify(msg); @@ -170,26 +205,26 @@ static void * RecvFromIPPort(void *arg) OpalPrint("%s: Skipping invalid packet\n", PROGNAME); continue; } + + if (cnt > msg->length) { + OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n", + PROGNAME, RecvID, cnt, msg->length); + } + + for (int i = 0; i < msg->length; i++) + mdldata[i] = (double) msg->data[i].f; /* Update OPAL model */ OpalSetAsyncRecvIconStatus(msg->sequence, RecvID); /* Set the Status to the message ID */ +#elif PROTOCOL == GTNET_SKT + for (int i = 0; i < cnt; i++) + mdldata[i] = (double) msg[i]; +#else + #error Unknown protocol +#endif + OpalSetAsyncRecvIconError(0, RecvID); /* Set the Error to 0 */ - /* Get the number of signals to send back to the model */ - OpalGetAsyncRecvIconDataLength(&mdldata_size, RecvID); - if (mdldata_size / sizeof(double) > MAX_VALUES) { - OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds allowed maximum (%d)\n", - PROGNAME, RecvID, mdldata_size / sizeof(double), MAX_VALUES); - return NULL; - } - - if (mdldata_size / sizeof(double) > msg->length) - OpalPrint("%s: Number of signals for RecvID=%d (%d) exceeds what was received (%d)\n", - PROGNAME, RecvID, mdldata_size / sizeof(double), msg->length); - - for (i = 0; i < msg->length; i++) - mdldata[i] = (double) msg->data[i].f; - OpalSetAsyncRecvIconData(mdldata, mdldata_size, RecvID); /* Before continuing, we make sure that the real-time model From 5e3e79b3982976ca6339cda8a9b182fe541abaef Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 12:10:15 +0200 Subject: [PATCH 13/16] updated submodule for OPAL-RT libraries --- thirdparty/libopal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/libopal b/thirdparty/libopal index 16b8a3b49..df13cf489 160000 --- a/thirdparty/libopal +++ b/thirdparty/libopal @@ -1 +1 @@ -Subproject commit 16b8a3b49af56fecd2b3734083fb4af9ea4a0192 +Subproject commit df13cf489f23564fe3507ca948cafe49c0849db2 From 9447d791f47952502718af07eb6bed6ae56e5ca3 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 12:21:51 +0200 Subject: [PATCH 14/16] asyncip: updated RT-LAB example project --- clients/opal/README.md | 41 ++++++++++++------- clients/opal/{udp => villas_udp}/.project | 0 .../com.opalrt.rtlab.ui.application.prefs | 0 .../models/send_receive/.gitignore | 0 .../models/send_receive/Makefile.mk | 0 .../models/send_receive/include/config.h | 0 .../models/send_receive/include/msg.h | 0 .../models/send_receive/include/msg_format.h | 0 .../models/send_receive/include/socket.h | 0 .../models/send_receive/include/utils.h | 0 .../models/send_receive/send_receive.llm | 9 ++-- .../models/send_receive/send_receive.mdl | 0 .../models/send_receive/src/compat.c | 0 .../models/send_receive/src/main.c | 0 .../models/send_receive/src/msg.c | 0 .../models/send_receive/src/socket.c | 0 .../models/send_receive/src/utils.c | 0 .../villas_udp.llp} | 6 +-- 18 files changed, 34 insertions(+), 22 deletions(-) rename clients/opal/{udp => villas_udp}/.project (100%) rename clients/opal/{udp => villas_udp}/.settings/com.opalrt.rtlab.ui.application.prefs (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/.gitignore (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/Makefile.mk (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/include/config.h (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/include/msg.h (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/include/msg_format.h (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/include/socket.h (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/include/utils.h (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/send_receive.llm (92%) rename clients/opal/{udp => villas_udp}/models/send_receive/send_receive.mdl (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/src/compat.c (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/src/main.c (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/src/msg.c (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/src/socket.c (100%) rename clients/opal/{udp => villas_udp}/models/send_receive/src/utils.c (100%) rename clients/opal/{udp/s2ss_tests.llp => villas_udp/villas_udp.llp} (63%) diff --git a/clients/opal/README.md b/clients/opal/README.md index 629f87b1a..ee8f73aa3 100644 --- a/clients/opal/README.md +++ b/clients/opal/README.md @@ -1,14 +1,20 @@ # Asynchronous Process interface to VILLASnode / GTNET-SKT -To "models" folder of OPAL project folder copy: -folder: include -folder: src -file: villas.mk +## Add AsyncIP to new project ----------------------------------------------- +#### Step 1 -.llm file should contain the following: -note: path to libOpalAsyncApiCore.a depends on version of RT-Lab +Copy the following files to the _models_ folder of the RT-LAB project: + +- Folder: `include/` +- Folder: `src/` +- File: `Makefile.mk` + +#### Step 2 + +The `.llm` file should contain the following lines: + +**Note:** path to libOpalAsyncApiCore.a depends on version of RT-Lab ``` [ExtraPutFilesComp] @@ -18,27 +24,32 @@ include\msg.h=Ascii include\msg_format.h=Ascii include\socket.h=Ascii include\utils.h=Ascii -villas.mk=Ascii +Makefile.mk=Ascii src\msg.c=Ascii src\main.c=Ascii src\socket.c=Ascii src\utils.c=Ascii +src\compat.c=Ascii ``` --------------------------------------------------- +#### Step 3 In RT-Lab under Files tab, we should see the files listed above for .llm file --------------------------------------------------- +#### Step 4 -Development tab -> Compiler -> Compiler Command (makefile) add the following command +In RT-LAB model settings: Development tab -> Compiler -> Compiler Command (makefile) add the following command + +``` /usr/bin/make -f /usr/opalrt/common/bin/opalmodelmk +``` --------------------------------------------------- +#### Step 5 -max umber of values in UDP packets: -there’s a „#define“ inside the implementation which must be changed accordingly. -The #define is in file: model_directory/include/config.h There you will find a directive called MAX_VALUES. +Maximum number of values in UDP packets: + +There’s a `#define` inside the implementation which must be changed accordingly. +The #define is in file: `model_directory/include/config.h` There you will find a directive called MAX_VALUES. # Troubleshooting diff --git a/clients/opal/udp/.project b/clients/opal/villas_udp/.project similarity index 100% rename from clients/opal/udp/.project rename to clients/opal/villas_udp/.project diff --git a/clients/opal/udp/.settings/com.opalrt.rtlab.ui.application.prefs b/clients/opal/villas_udp/.settings/com.opalrt.rtlab.ui.application.prefs similarity index 100% rename from clients/opal/udp/.settings/com.opalrt.rtlab.ui.application.prefs rename to clients/opal/villas_udp/.settings/com.opalrt.rtlab.ui.application.prefs diff --git a/clients/opal/udp/models/send_receive/.gitignore b/clients/opal/villas_udp/models/send_receive/.gitignore similarity index 100% rename from clients/opal/udp/models/send_receive/.gitignore rename to clients/opal/villas_udp/models/send_receive/.gitignore diff --git a/clients/opal/udp/models/send_receive/Makefile.mk b/clients/opal/villas_udp/models/send_receive/Makefile.mk similarity index 100% rename from clients/opal/udp/models/send_receive/Makefile.mk rename to clients/opal/villas_udp/models/send_receive/Makefile.mk diff --git a/clients/opal/udp/models/send_receive/include/config.h b/clients/opal/villas_udp/models/send_receive/include/config.h similarity index 100% rename from clients/opal/udp/models/send_receive/include/config.h rename to clients/opal/villas_udp/models/send_receive/include/config.h diff --git a/clients/opal/udp/models/send_receive/include/msg.h b/clients/opal/villas_udp/models/send_receive/include/msg.h similarity index 100% rename from clients/opal/udp/models/send_receive/include/msg.h rename to clients/opal/villas_udp/models/send_receive/include/msg.h diff --git a/clients/opal/udp/models/send_receive/include/msg_format.h b/clients/opal/villas_udp/models/send_receive/include/msg_format.h similarity index 100% rename from clients/opal/udp/models/send_receive/include/msg_format.h rename to clients/opal/villas_udp/models/send_receive/include/msg_format.h diff --git a/clients/opal/udp/models/send_receive/include/socket.h b/clients/opal/villas_udp/models/send_receive/include/socket.h similarity index 100% rename from clients/opal/udp/models/send_receive/include/socket.h rename to clients/opal/villas_udp/models/send_receive/include/socket.h diff --git a/clients/opal/udp/models/send_receive/include/utils.h b/clients/opal/villas_udp/models/send_receive/include/utils.h similarity index 100% rename from clients/opal/udp/models/send_receive/include/utils.h rename to clients/opal/villas_udp/models/send_receive/include/utils.h diff --git a/clients/opal/udp/models/send_receive/send_receive.llm b/clients/opal/villas_udp/models/send_receive/send_receive.llm similarity index 92% rename from clients/opal/udp/models/send_receive/send_receive.llm rename to clients/opal/villas_udp/models/send_receive/send_receive.llm index 8516670ae..a8165608c 100644 --- a/clients/opal/udp/models/send_receive/send_receive.llm +++ b/clients/opal/villas_udp/models/send_receive/send_receive.llm @@ -37,22 +37,23 @@ INTERNAL_IGN_SOURCE_FILE=sfun_gen_async_ctrl.c sfun_recv_async.c sfun_send_async INTERNAL_LIBRARY2=-lOpalAsyncApiR2013a INTERNAL_LIBRARY3=-lOpalAsyncApiCore [ExtraGetFilesComp_1_RT_LAB] -s2ss=Binary|Async_Proc +AsyncIP=Binary|Async_Proc [ExtraPutFilesComp] include\config.h=Ascii include\msg.h=Ascii include\msg_format.h=Ascii include\socket.h=Ascii include\utils.h=Ascii -villas.mk=Ascii +Makefile.mk=Ascii src\msg.c=Ascii src\main.c=Ascii src\socket.c=Ascii src\utils.c=Ascii +src\compat.c=Ascii [ExtraPutFilesComp_1_RT_LAB] C:\OPAL-RT\RT-LAB\v11.0.2.410\common\lib\redhawk\libOpalAsyncApiCore.a=Binary|Other [ExtraPutFilesLoad_1_RT_LAB] -.\send_receive_sm_model\OpREDHAWKtarget\s2ss=Binary|Async_Proc +.\send_receive_sm_model\OpREDHAWKtarget\AsyncIP=Binary|Async_Proc [General] ATT_CHECKSUM1=1967915764 ATT_CHECKSUM2=1071010712 @@ -71,7 +72,7 @@ AutoRetrieveRtlab=ON CompilerVersion=AUTOMATIC DESCRIPTION= DinamoFlag=OFF -FILENAME=D:\svo\s2ss\clients\opal\udp\models\send_receive\send_receive.mdl +FILENAME=D:\svo\s2ss\clients\opal\villas_udp\models\send_receive\send_receive.mdl FORCE_RECOMPILE=0 IMPORTED_GLOBAL_VARIABLES=1 LastCompileRtlabVersion=v11.0.2.410 diff --git a/clients/opal/udp/models/send_receive/send_receive.mdl b/clients/opal/villas_udp/models/send_receive/send_receive.mdl similarity index 100% rename from clients/opal/udp/models/send_receive/send_receive.mdl rename to clients/opal/villas_udp/models/send_receive/send_receive.mdl diff --git a/clients/opal/udp/models/send_receive/src/compat.c b/clients/opal/villas_udp/models/send_receive/src/compat.c similarity index 100% rename from clients/opal/udp/models/send_receive/src/compat.c rename to clients/opal/villas_udp/models/send_receive/src/compat.c diff --git a/clients/opal/udp/models/send_receive/src/main.c b/clients/opal/villas_udp/models/send_receive/src/main.c similarity index 100% rename from clients/opal/udp/models/send_receive/src/main.c rename to clients/opal/villas_udp/models/send_receive/src/main.c diff --git a/clients/opal/udp/models/send_receive/src/msg.c b/clients/opal/villas_udp/models/send_receive/src/msg.c similarity index 100% rename from clients/opal/udp/models/send_receive/src/msg.c rename to clients/opal/villas_udp/models/send_receive/src/msg.c diff --git a/clients/opal/udp/models/send_receive/src/socket.c b/clients/opal/villas_udp/models/send_receive/src/socket.c similarity index 100% rename from clients/opal/udp/models/send_receive/src/socket.c rename to clients/opal/villas_udp/models/send_receive/src/socket.c diff --git a/clients/opal/udp/models/send_receive/src/utils.c b/clients/opal/villas_udp/models/send_receive/src/utils.c similarity index 100% rename from clients/opal/udp/models/send_receive/src/utils.c rename to clients/opal/villas_udp/models/send_receive/src/utils.c diff --git a/clients/opal/udp/s2ss_tests.llp b/clients/opal/villas_udp/villas_udp.llp similarity index 63% rename from clients/opal/udp/s2ss_tests.llp rename to clients/opal/villas_udp/villas_udp.llp index ff62308f7..544f22ba7 100644 --- a/clients/opal/udp/s2ss_tests.llp +++ b/clients/opal/villas_udp/villas_udp.llp @@ -6,14 +6,14 @@ 134.130.169.90:25252 C2357876-6DB6-422F-ABD4-AB47963523A2 ON - D:\svo\s2ss\clients\opal\udp\s2ss_tests.llp + D:\svo\s2ss\clients\opal\villas_udp\villas_udp.llp models/send_receive/send_receive.mdl - D:/svo/s2ss/clients/opal/udp/models/send_receive/send_receive.mdl - //E265/D/svo/s2ss/clients/opal/udp/models/send_receive/send_receive.mdl + D:/svo/s2ss/clients/opal/villas_udp/models/send_receive/send_receive.mdl + //E265/D/svo/s2ss/clients/opal/villas_udp/models/send_receive/send_receive.mdl From 8c4f291fd9e0cb0eb76d7f9d295d08669a6f8d52 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 13:22:55 +0200 Subject: [PATCH 15/16] changed byte-order for websocket messages to little-endian --- include/villas/webmsg.h | 35 ++++++++++++++++++++++ include/villas/webmsg_format.h | 12 ++++---- lib/nodes/websocket.c | 2 +- lib/webmsg.c | 54 ++++++++++++++++++++++++++++++++++ web/socket/msg.js | 53 +++++++-------------------------- 5 files changed, 107 insertions(+), 49 deletions(-) create mode 100644 include/villas/webmsg.h create mode 100644 lib/webmsg.c diff --git a/include/villas/webmsg.h b/include/villas/webmsg.h new file mode 100644 index 000000000..4cf7f6838 --- /dev/null +++ b/include/villas/webmsg.h @@ -0,0 +1,35 @@ +/** Message related functions + * + * @file + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ + +#pragma once + +/* Forward declarations. */ +struct webmsg; + +/** Swaps the byte-order of the message. + * + * Message are always transmitted in network (big endian) byte order. + * + * @param m A pointer to the message + */ +void webmsg_hdr_ntoh(struct webmsg *m); + +void webmsg_hdr_hton(struct webmsg *m); + +void webmsg_ntoh(struct webmsg *m); + +void webmsg_hton(struct webmsg *m); + +/** Check the consistency of a message. + * + * The functions checks the header fields of a message. + * + * @param m A pointer to the message + * @retval 0 The message header is valid. + * @retval <0 The message header is invalid. + */ +int msg_verify(struct webmsg *m); \ No newline at end of file diff --git a/include/villas/webmsg_format.h b/include/villas/webmsg_format.h index 8978bdba1..0ec8080ed 100644 --- a/include/villas/webmsg_format.h +++ b/include/villas/webmsg_format.h @@ -1,4 +1,7 @@ -/** Binary websocket message format +/** Binary websocket message format. + * + * Note: Messages sent by the 'websocket' node-type are always send in little endian byte-order! + * This is different from the messages send with the 'socket' node-type! * * @file * @author Steffen Vogel @@ -20,7 +23,7 @@ #define WEBMSG_TYPE_STOP 2 /**< Message marks the end of a simulation case */ /** The total size in bytes of a message */ -#define WEBMSG_LEN(values) (sizeof(struct webmsg) + MSG_DATA_LEN(values)) +#define WEBMSG_LEN(values) (sizeof(struct webmsg) + WEBMSG_DATA_LEN(values)) /** The length of \p values values in bytes. */ #define WEBMSG_DATA_LEN(values) (sizeof(float) * (values)) @@ -32,7 +35,6 @@ #define WEBMSG_INIT(len, seq) (struct webmsg) {\ .version = WEBMSG_VERSION, \ .type = WEBMSG_TYPE_DATA, \ - .endian = WEBMSG_ENDIAN_HOST, \ .length = len, \ .sequence = seq \ } @@ -49,9 +51,9 @@ **/ struct webmsg { - unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ - unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ unsigned rsvd1 : 2; /**< Reserved bits */ + unsigned type : 2; /**< Data or control message (see MSG_TYPE_*) */ + unsigned version: 4; /**< Specifies the format of the remaining message (see MGS_VERSION) */ uint8_t id; /**< The node index from / to which this sample received / sent to. * Corresponds to the index of the node in the http://localhost/nodes.json array. */ diff --git a/lib/nodes/websocket.c b/lib/nodes/websocket.c index 03df20766..8e84535db 100644 --- a/lib/nodes/websocket.c +++ b/lib/nodes/websocket.c @@ -13,6 +13,7 @@ #include #include "super_node.h" +#include "webmsg.h" #include "webmsg_format.h" #include "timing.h" #include "utils.h" @@ -119,7 +120,6 @@ static int websocket_connection_write(struct websocket_connection *c, struct sam msg->version = WEBMSG_VERSION; msg->type = WEBMSG_TYPE_DATA; - msg->endian = WEBMSG_ENDIAN_HOST; msg->length = smps[i]->length; msg->sequence = smps[i]->sequence; msg->id = c->node->id; diff --git a/lib/webmsg.c b/lib/webmsg.c new file mode 100644 index 000000000..489f9cd57 --- /dev/null +++ b/lib/webmsg.c @@ -0,0 +1,54 @@ +/** Websocket message related functions. + * + * @author Steffen Vogel + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC + *********************************************************************************/ + +#include + +#include "webmsg.h" +#include "msg_format.h" + +void webmsg_ntoh(struct webmsg *m) +{ + msg_hdr_ntoh(m); + + for (int i = 0; i < m->length; i++) + m->data[i].i = ntohl(m->data[i].i); +} + +void msg_hton(struct webmsg *m) +{ + for (int i = 0; i < m->length; i++) + m->data[i].i = htonl(m->data[i].i); + + webmsg_hdr_hton(m); +} + +void webmsg_hdr_hton(struct webmsg *m) +{ + m->length = htole16(m->length); + m->sequence = htonle32(m->sequence); + m->ts.sec = htonle32(m->ts.sec); + m->ts.nsec = htonle32(m->ts.nsec); +} + +void webmsg_hdr_ntoh(struct webmsg *m) +{ + m->length = le16tohs(m->length); + m->sequence = le32tohl(m->sequence); + m->ts.sec = le32tohl(m->ts.sec); + m->ts.nsec = le32tohl(m->ts.nsec); +} + +int webmsg_verify(struct webmsg *m) +{ + if (m->version != WEBMSG_VERSION) + return -1; + else if (m->type != WEBMSG_TYPE_DATA) + return -2; + else if ((m->rsvd1 != 0) || (m->rsvd2 != 0)) + return -3; + else + return 0; +} \ No newline at end of file diff --git a/web/socket/msg.js b/web/socket/msg.js index ad2a2f881..5d89535d0 100644 --- a/web/socket/msg.js +++ b/web/socket/msg.js @@ -1,8 +1,11 @@ -/** Javascript class for parsing binary messages +/** Javascript class for parsing binary messages. + * + * Note: Messages sent by the 'websocket' node-type are always send in little endian byte-order! + * This is different from the messages send with the 'socket' node-type! * * @file * @author Steffen Vogel - * @copyright 2016, Institute for Automation of Complex Power Systems, EONERC + * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC *********************************************************************************/ /** * @addtogroup websocket @@ -15,7 +18,6 @@ function Msg(c) { this.sequence = typeof c.sequence === 'undefined' ? 0 : c.sequence; this.length = typeof c.length === 'undefined' ? 0 : c.length; - this.endian = typeof c.endian === 'undefined' ? Msg.prototype.ENDIAN_LITTLE : c.endian; this.version = typeof c.version === 'undefined' ? Msg.prototype.VERSION : c.version; this.type = typeof c.type === 'undefined' ? Msg.prototype.TYPE_DATA : c.type; this.id = typeof c.id === 'undefined' ? -1 : c.id; @@ -32,11 +34,7 @@ Msg.prototype.VERSION = 1; Msg.prototype.TYPE_DATA = 0; /**< Message contains float values */ -Msg.prototype.ENDIAN_LITTLE = 0; /**< Message values are in little endian format (float too!) */ -Msg.prototype.ENDIAN_BIG = 1; /**< Message values are in bit endian format */ - /* Some offsets in the binary message */ -Msg.prototype.OFFSET_ENDIAN = 1; Msg.prototype.OFFSET_TYPE = 2; Msg.prototype.OFFSET_VERSION = 4; @@ -48,30 +46,20 @@ Msg.bytes = function(len) Msg.fromArrayBuffer = function(data) { var bits = data.getUint8(0); - var endian = (bits >> Msg.prototype.OFFSET_ENDIAN) & 0x1 ? 0 : 1; var msg = new Msg({ - endian: (bits >> Msg.prototype.OFFSET_ENDIAN) & 0x1, version: (bits >> Msg.prototype.OFFSET_VERSION) & 0xF, type: (bits >> Msg.prototype.OFFSET_TYPE) & 0x3, - id: data.getUint8( 0x01, endian), - length: data.getUint16(0x02, endian), - sequence: data.getUint32(0x04, endian), - timestamp: data.getUint32(0x08, endian) * 1e3 + - data.getUint32(0x0C, endian) * 1e-6, + id: data.getUint8( 0x01), + length: data.getUint16(0x02, 1), + sequence: data.getUint32(0x04, 1), + timestamp: data.getUint32(0x08, 1) * 1e3 + + data.getUint32(0x0C, 1) * 1e-6, }); msg.blob = new DataView( data.buffer, data.byteOffset + 0x00, Msg.bytes(msg.length)); msg.data = new Float32Array(data.buffer, data.byteOffset + 0x10, msg.length); - if (msg.endian != host_endianess()) { - console.warn("Message is not given in host endianess!"); - - var data = new Uint32Array(msg.blob, 0x10); - for (var i = 0; i < data.length; i++) - data[i] = swap32(data[i]); - } - return msg; } @@ -101,7 +89,6 @@ Msg.prototype.toArrayBuffer = function() view = new DataView(buffer); var bits = 0; - bits |= (this.endian & 0x1) << Msg.prototype.OFFSET_ENDIAN; bits |= (this.version & 0xF) << Msg.prototype.OFFSET_VERSION; bits |= (this.type & 0x3) << Msg.prototype.OFFSET_TYPE; @@ -121,24 +108,4 @@ Msg.prototype.toArrayBuffer = function() return buffer; } -/** @todo parsing of big endian messages not yet supported */ -function swap16(val) -{ - return ((val & 0xFF) << 8) - | ((val >> 8) & 0xFF); -} - -function swap32(val) { - return ((val & 0xFF) << 24) - | ((val & 0xFF00) << 8) - | ((val >> 8) & 0xFF00) - | ((val >> 24) & 0xFF); -} - -function host_endianess() { - var buffer = new ArrayBuffer(2); - new DataView(buffer).setInt16(0, 256, true /* littleEndian */); - return new Int16Array(buffer)[0] === 256 ? 0 : 1; // Int16Array uses the platform's endianness. -}; - /** @} */ \ No newline at end of file From 48a5b8ed0d4a4d8f24bfe2ee13e3f52053b74734 Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Mon, 24 Apr 2017 13:06:59 +0200 Subject: [PATCH 16/16] updated build-system to build AsyncIP by default --- Dockerfile.dev | 15 +++++++++------ Makefile | 2 +- clients/Makefile.inc | 17 +++++++++-------- .../villas_udp/models/send_receive/Makefile.mk | 4 ++-- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index 452a7c6a0..7c56160be 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -16,8 +16,7 @@ FROM fedora:latest MAINTAINER Steffen Vogel # Toolchain -RUN dnf -y update && \ - dnf -y install \ +RUN dnf -y install \ gcc gcc-c++ \ pkgconfig make cmake \ autoconf automake autogen libtool \ @@ -25,8 +24,7 @@ RUN dnf -y update && \ texinfo git # Dependencies -RUN dnf -y update && \ - dnf -y install \ +RUN dnf -y install \ openssl openssl-devel \ libconfig-devel \ libnl3-devel \ @@ -34,8 +32,7 @@ RUN dnf -y update && \ jansson-devel # Several tools only needed for developement and testing -RUN dnf -y update && \ - dnf -y install \ +RUN dnf -y install \ doxygen dia graphviz \ openssh-clients \ rpmdevtools rpm-build \ @@ -45,6 +42,12 @@ RUN dnf -y update && \ valgrind \ gdb +# 32bit versions of some standard libraries for RT-LAB code +RUN dnf -y install \ + libstdc++-devel.i686 \ + libuuid-devel.i686 \ + glibc-devel.i686 + # Tools for debugging, coverage, profiling RUN pip install \ gcovr diff --git a/Makefile b/Makefile index a29611331..5d40c3f88 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ ################################################################################### # Project modules -MODULES = lib plugins src tests thirdparty tools packaging doc etc web +MODULES = clients lib plugins src tests thirdparty tools packaging doc etc web # Default prefix for install target PREFIX ?= /usr/local diff --git a/clients/Makefile.inc b/clients/Makefile.inc index 1f067acde..94fb31e70 100644 --- a/clients/Makefile.inc +++ b/clients/Makefile.inc @@ -1,19 +1,20 @@ -ASYNCIP_PATH = $(SRCDIR)/clients/opal/udp/models/send_receive +ASYNCIP_PATH = $(SRCDIR)/clients/opal/villas_udp/models/send_receive -clients: clients-opal - -clients-opal: - $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk AsyncIP \ - RTLAB_INTEL_COMPILER=0 \ +ASYNCIP_OPTS = RTLAB_INTEL_COMPILER=0 \ PROTOCOL=GTNET_SKT \ OPAL_LIBS="-lSystem -luuid" \ OPAL_LIBPATH=-L$(SRCDIR)/thirdparty/libopal/ \ OPAL_INCPATH=-I$(SRCDIR)/thirdparty/libopal/include/opal +clients: clients-opal + +clients-opal: + $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk AsyncIP $(ASYNCIP_OPTS) + clean-clients: - $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk clean + $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk clean $(ASYNCIP_OPTS) install-clients: - $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk install + $(MAKE) -C $(ASYNCIP_PATH) -f Makefile.mk install $(ASYNCIP_OPTS) .PHONY: clients clean-clients install-clients \ No newline at end of file diff --git a/clients/opal/villas_udp/models/send_receive/Makefile.mk b/clients/opal/villas_udp/models/send_receive/Makefile.mk index b56efb1d6..c5a0c6a3e 100644 --- a/clients/opal/villas_udp/models/send_receive/Makefile.mk +++ b/clients/opal/villas_udp/models/send_receive/Makefile.mk @@ -1,6 +1,6 @@ TARGET = AsyncIP -VPATH = $(SRCDIR)/src +VPATH = src RTLAB_INTEL_COMPILER ?= 1 @@ -49,7 +49,7 @@ install: $(TARGET) install -m 0755 -D -t $(DESTDIR)$(PREFIX)/bin $(TARGET) clean: - rm -f $(OBJS) $(TARGET) + rm -f $(OBJS) $(OBJS:%.o=%.d) $(TARGET) $(TARGET): $(OBJS) $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)