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