diff --git a/include/villas/io/msg.h b/include/villas/io/msg.h index c4094d8db..9c520d06d 100644 --- a/include/villas/io/msg.h +++ b/include/villas/io/msg.h @@ -30,6 +30,10 @@ struct msg; struct sample; struct io; +enum msg_flags { + MSG_WEB = (1 << 16) /**< Use webmsg format (everying little endian) */ +}; + /** Swaps the byte-order of the message. * * Message are always transmitted in network (big endian) byte order. diff --git a/include/villas/io/webmsg.h b/include/villas/io/webmsg.h deleted file mode 100644 index c5800eb75..000000000 --- a/include/villas/io/webmsg.h +++ /dev/null @@ -1,51 +0,0 @@ -/** Message related functions - * - * @file - * @author Steffen Vogel - * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC - * @license GNU General Public License (version 3) - * - * VILLASnode - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************************/ - -#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); diff --git a/include/villas/io/webmsg_format.h b/include/villas/io/webmsg_format.h deleted file mode 100644 index d58d3d773..000000000 --- a/include/villas/io/webmsg_format.h +++ /dev/null @@ -1,89 +0,0 @@ -/** 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 - * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC - * @license GNU General Public License (version 3) - * - * VILLASnode - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************************/ - -#pragma once - -#include - -/** The current version number for the message format */ -#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 */ - -/** The total size in bytes of a message */ -#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)) - -/** The offset to the first data value in a message. */ -#define WEBMSG_DATA_OFFSET(msg) ((char *) (msg) + offsetof(struct webmsg, data)) - -/** Initialize a message with default values */ -#define WEBMSG_INIT(len, seq) (struct webmsg) {\ - .version = WEBMSG_VERSION, \ - .type = WEBMSG_TYPE_DATA, \ - .length = len, \ - .sequence = seq \ -} - -/** The timestamp of a message in struct timespec format */ -#define WEBMSG_TS(msg) (struct timespec) {\ - .tv_sec = (msg)->ts.sec, \ - .tv_nsec = (msg)->ts.nsec \ -} - -/** This message format is used by all clients - * - * @diafile msg_format.dia - **/ -struct webmsg -{ - 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. */ - - 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. */ - struct { - uint32_t sec; /**< Seconds since 1970-01-01 00:00:00 */ - uint32_t nsec; /**< Nanoseconds of the current second. */ - } ts; - - /** The message payload. */ - union { - float f; /**< Floating point values. */ - uint32_t i; /**< Integer values. */ - } data[]; -} __attribute__((packed)); diff --git a/lib/io/msg.c b/lib/io/msg.c index b386f050d..5abf7abdd 100644 --- a/lib/io/msg.c +++ b/lib/io/msg.c @@ -76,8 +76,6 @@ int msg_to_sample(struct msg *msg, struct sample *smp) { int ret; - msg_ntoh(msg); - ret = msg_verify(msg); if (ret) return -1; @@ -115,8 +113,6 @@ int msg_from_sample(struct msg *msg, struct sample *smp) } } - msg_hton(msg); - return 0; } @@ -126,14 +122,23 @@ int msg_sprint(char *buf, size_t len, size_t *wbytes, struct sample *smps[], uns char *ptr = buf; for (i = 0; i < cnt; i++) { - if (ptr + MSG_LEN(smps[i]->length) > buf + len) + struct msg *msg = (struct msg *) ptr; + struct sample *smp = smps[i]; + + if (ptr + MSG_LEN(smp->length) > buf + len) break; - ret = msg_from_sample((struct msg *) ptr, smps[i]); + ret = msg_from_sample(msg, smp); if (ret) return ret; - ptr += MSG_LEN(smps[i]->length); + if (flags & MSG_WEB) { + /** @todo convert to little endian */ + } + else + msg_hton(msg); + + ptr += MSG_LEN(smp->length); } if (wbytes) @@ -154,6 +159,7 @@ int msg_sscan(char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsi for (i = 0; i < cnt; i++) { struct msg *msg = (struct msg *) ptr; + struct sample *smp = smps[i]; /* Check if length field is still in buffer bounaries */ if ((char *) &msg->length + sizeof(msg->length) > buf + len) { @@ -166,12 +172,18 @@ int msg_sscan(char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsi warn("Invalid msg received: reason=2, msglen=%zu, len=%zu, ptr=%p, buf+%p, i=%u", MSG_LEN(ntohs(msg->length)), len, ptr, buf, i); break; } - - ret = msg_to_sample((struct msg *) ptr, smps[i]); + + if (*flags & MSG_WEB) { + /** @todo convert to little endian */ + } + else + msg_ntoh(msg); + + ret = msg_to_sample((struct msg *) ptr, smp); if (ret) return ret; - ptr += MSG_LEN(smps[i]->length); + ptr += MSG_LEN(smp->length); } if (rbytes) @@ -180,7 +192,7 @@ int msg_sscan(char *buf, size_t len, size_t *rbytes, struct sample *smps[], unsi return i; } -static struct plugin p = { +static struct plugin p1 = { .name = "msg", .description = "VILLAS binary network format", .type = PLUGIN_TYPE_IO, @@ -192,4 +204,17 @@ static struct plugin p = { }, }; -REGISTER_PLUGIN(&p); +static struct plugin p2 = { + .name = "webmsg", + .description = "VILLAS binary network format for websockets", + .type = PLUGIN_TYPE_IO, + .io = { + .sprint = msg_sprint, + .sscan = msg_sscan, + .size = 0, + .flags = IO_FORMAT_BINARY | MSG_WEB + }, +}; + +REGISTER_PLUGIN(&p1); +REGISTER_PLUGIN(&p2); diff --git a/lib/io/webmsg.c b/lib/io/webmsg.c deleted file mode 100644 index 34d74a08b..000000000 --- a/lib/io/webmsg.c +++ /dev/null @@ -1,182 +0,0 @@ -/** Websocket message related functions. - * - * @author Steffen Vogel - * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC - * @license GNU General Public License (version 3) - * - * VILLASnode - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************************/ - -#ifdef __MACH__ - #include "compat.h" -#elif defined(__linux__) - #include -#endif - -#include "sample.h" -#include "plugin.h" -#include "formats/webmsg.h" -#include "formats/webmsg_format.h" - -void webmsg_ntoh(struct webmsg *m) -{ - webmsg_hdr_ntoh(m); - - for (int i = 0; i < m->length; i++) - m->data[i].i = le32toh(m->data[i].i); -} - -void webmsg_hton(struct webmsg *m) -{ - for (int i = 0; i < m->length; i++) - m->data[i].i = htole32(m->data[i].i); - - webmsg_hdr_hton(m); -} - -void webmsg_hdr_hton(struct webmsg *m) -{ - m->length = htole16(m->length); - m->sequence = htole32(m->sequence); - m->ts.sec = htole32(m->ts.sec); - m->ts.nsec = htole32(m->ts.nsec); -} - -void webmsg_hdr_ntoh(struct webmsg *m) -{ - m->length = le16toh(m->length); - m->sequence = le32toh(m->sequence); - m->ts.sec = le32toh(m->ts.sec); - m->ts.nsec = le32toh(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) - return -3; - else - return 0; -} - -int webmsg_to_sample(struct webmsg *msg, struct sample *smp) -{ - int ret; - - webmsg_ntoh(msg); - - ret = webmsg_verify(msg); - if (ret) - return -1; - - smp->length = MIN(msg->length, smp->capacity); - smp->sequence = msg->sequence; - smp->id = msg->id; - smp->ts.origin = WEBMSG_TS(msg); - smp->ts.received.tv_sec = -1; - smp->ts.received.tv_nsec = -1; - - memcpy(smp->data, msg->data, SAMPLE_DATA_LEN(smp->length)); - - return 0; -} - -int webmsg_from_sample(struct webmsg *msg, struct sample *smp) -{ - *msg = WEBMSG_INIT(smp->length, smp->sequence); - - msg->id = smp->id; - msg->ts.sec = smp->ts.origin.tv_sec; - msg->ts.nsec = smp->ts.origin.tv_nsec; - - memcpy(msg->data, smp->data, WEBMSG_DATA_LEN(smp->length)); - - msg_hton(msg); - - return 0; -} - -size_t io_format_webmsg_length(struct sample *smps[], size_t cnt) -{ - size_t sz = 0; - - for (int i = 0; i < cnt; i++) - sz += WEBMSG_LEN(smps[i]->length); - - return sz; -} - -size_t io_format_webmsg_sprint(char *buf, size_t len, struct sample *smps[], size_t cnt, int flags) -{ - int ret, i = 0; - char *ptr = buf; - - struct webmsg *msg = (struct webmsg *) ptr; - struct sample *smp = smps[i]; - - while (ptr < buf + len && i < cnt) { - ret = webmsg_from_sample(msg, smp); - if (ret) - return ret; - - ptr += WEBMSG_LEN(smp->length); - - msg = (struct webmsg *) ptr; - smp = smps[++i]; - } - - return ptr - buf; -} - -size_t io_format_webmsg_sscan(char *buf, size_t len, struct sample *smps[], size_t cnt, int *flags) -{ - int ret, i = 0; - char *ptr = buf; - - struct webmsg *msg = (struct webmsg *) ptr; - struct sample *smp = smps[i]; - - while (ptr < buf + len && i < cnt) { - ret = webmsg_to_sample(msg, smp); - if (ret) - return ret; - - ptr += WEBMSG_LEN(smp->length); - - msg = (struct webmsg *) ptr; - smp = smps[++i]; - } - - return i; -} - -static struct plugin p = { - .name = "webmsg", - .description = "VILLAS binary format for websockets", - .type = PLUGIN_TYPE_FORMAT, - .format = { - .length = io_format_webmsg_length, - .sprint = io_format_webmsg_sprint, - .sscan = io_format_webmsg_sscan, - .flags = IO_FORMAT_BINARY, - .size = 0 - }, -}; - -REGISTER_PLUGIN(&p);