@@ -20,6 +20,10 @@ needed. This should offer multiple TCP connections and contain the necessary
2020logic to map requests/replies from/to those network connections onto/from the
2121serial connection to the actual SEC node.
2222
23+ Finally, SECoP messages can also be exchanged over WebSockets, which is useful
24+ for interacting directly with browsers/JavaScript clients, see
25+ :ref: `websockets `.
26+
2327
2428Transfer modes
2529--------------
@@ -912,3 +916,75 @@ to be sent before it can continue as before.
912916
913917 | :issue:`004 The Timeout SEC Node Property`
914918 | :issue:`006 Keep Alive`
919+
920+
921+ .. _websockets :
922+
923+ SECoP over WebSockets
924+ ---------------------
925+
926+ Since browser (i.e. HTML+JavaScript) based human interface solutions are more
927+ and more important, and JavaScript lacks traditional socket based APIs,
928+ exchanging raw SECoP messages is not an option. The best alternative is
929+ WebSockets (RFC :rfc: `6455 `), which are a relatively overhead-free way of
930+ exchanging messages between two endpoints in an arbitrary pattern.
931+
932+ See also `SECoP RFC 7 `_.
933+
934+ Implementation in a SEC node
935+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
936+
937+ After opening a connection, if the first message the SEC node receives starts
938+ with ``GET / ``, it treats the connection as a WebSocket connection, i.e. it
939+ negotiates the connection using a prelude of HTTP requests, after which the
940+ connection continues using the WebSocket protocol in both directions.
941+
942+ Since WebSockets provide reliable framing, every SECoP message is sent in a
943+ frame. The line ending added to separate messages over raw TCP is therefore
944+ unneded, but remains valid. Messages are sent as TEXT frames.
945+
946+ Everything else (message structure and semantics) remains unchanged.
947+
948+ .. note ::
949+
950+ If the SEC node doesn't want to support WebSockets, no further action is
951+ required. It will reply with the standard SECoP error messages, and the
952+ client will abort the connection attempt.
953+
954+ A minimal implementation of the HTTP prelude is pretty small, does not have
955+ a lot of complexity, and can be implemented even on microcontrollers `in
956+ about 200 lines of code
957+ <https://github.com/SampleEnvironment/microSECoP/blob/master/src/http.rs> `_.
958+
959+ Implementation in a client
960+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
961+
962+ On the WebSocket client side, making a connection is as easy as opening a
963+ connection and start sending request messages, handling response messages as
964+ they come in. A very minimal example in JavaScript::
965+
966+ function on_connect(event) {
967+ // On initial connect, we should ask for identification
968+ event.target.send('*IDN?');
969+ }
970+
971+ function on_message(event) {
972+ let msg = event.data;
973+ // Handle response to initial *IDN? and request descriptive data
974+ if (msg.startsWith('ISSE')) {
975+ event.target.send('describe');
976+ return;
977+ }
978+ // Parse `msg` as a SECoP message here, and react to it
979+ }
980+
981+ let ws = new WebSocket('ws://node:10767');
982+ ws.addEventListener('open', on_connect);
983+ ws.addEventListener('message', on_message);
984+ // Should also listen on 'close' and 'error' events
985+
986+ // Whenever needed, send messages, for example:
987+ ws.send('change mod:param 42');
988+
989+
990+ .. _SECoP RFC 7 : https://github.com/SampleEnvironment/SECoP/blob/master/rfcs/RFC-007-websockets.rst
0 commit comments