@@ -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