aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUnavailableDev <ggwildplay@gmail.com>2023-01-17 21:27:18 +0100
committerUnavailableDev <ggwildplay@gmail.com>2023-01-17 21:27:18 +0100
commit4c204bfc70dea53ccb6b7a7fd74d01a2c4b6b358 (patch)
tree9b204adbbc80060f2eafeb21406679758a72d317
parent0f0202d979ed24f8640cd239fdad23d6154a8f61 (diff)
parentc89d8caccdccc5c1ceb299addc1adc63bfb2d156 (diff)
Merge branch 'dev' of https://github.com/lonkaars/avans-domotica into dev
-rw-r--r--docs/design.md49
-rw-r--r--docs/fig.drawio2
-rw-r--r--docs/img/fig-AsyncCommunication.svg1
-rw-r--r--docs/img/fig-protocol.svg3
4 files changed, 46 insertions, 9 deletions
diff --git a/docs/design.md b/docs/design.md
index f63bad9..17e09cc 100644
--- a/docs/design.md
+++ b/docs/design.md
@@ -23,6 +23,13 @@ details are:
features to edit the configuration and node state, but all action handling is
happening on the nodes.
+
+# Framework
+
+
+
+
+
# Custom serial protocol
The border router node communicates with the QT application using a USART
@@ -30,19 +37,41 @@ interface, over which our custom protocol is used to send and receive formatted
data.
The protocol itself is in a binary format to save on bandwidth and memory
-consumption on the node side. Messages consist of a single starting byte
-(0xff), and following data which is derived from packed structs (a struct of
-which each field is adjacent in memory, without padding).
+consumption on the node side. The message data is derived from packed structs
+(a struct of which each field is adjacent in memory, without padding). Example
+binary messages with comments are provided in the source folder
+`shared/protocol-tests`.
+
+When messages are sent out by either side, they are prefixed with a single
+`0xff` byte to identify the start of a message. If a message contains a literal
+`0xff` byte, it will be escaped by the send function by sending the `0xff` byte
+twice.
All data that is sent starts with an opcode to represent the message type, and
a message id to uniquely identify each message for the purpose of replying to a
-specific message or request. Most messages are fixed-length, but messages that
+specific message request. Most messages are fixed-length, but messages that
have variable-length fields have extra logic in the parser module to handle
memory allocation. All message types implement their own handler function which
decodes the message back into a regular struct.
-Exact specifications of the protocol can be found in the source tree in
-markdown format, with included client and parser libaries.
+The following is an example in which the server notices that the client is
+connected, and the client requests a node to be provisioned into the network:
+
+![Example exchange between the client (QT) and server (border
+router)](img/fig-protocol.svg)
+
+The following details should be noted in this diagram:
+
+- Messages are numbered sequentially and independently by each side
+- Each message has a separate type
+- Response messages include the type of their 'parent' message
+- Response messages include a status
+
+Other important details:
+
+- 16-bit and 32-bit numbers are sent with network (big) endianness.
+- Messages are buffered until complete, so this protocol should be used over
+ unbuffered serial connections only.
# Asynchronous QT Serial port
@@ -76,7 +105,7 @@ For now, there are two semaphores created in the provisioner software. The first
<figure>
|Library|Version|
-|-------|-------|
+|:------|------:|
|Git|2.39.0|
|GCC|12.2.0|
|Qt|6.0.0|
@@ -93,9 +122,13 @@ For now, there are two semaphores created in the provisioner software. The first
# Data transfer between GUI and mesh network
## Asynchronous data handling
-Because the data will be received asynchronously, certain decisions will have to be made about how to deal with this. In this case the GUI or client sends out requests/tasks to the border router. The border node then responds after x time. In both cases this triggers a callback function on the receiving end, so that the data can be handled accordingly.
+
+Because the data will be received asynchronously, certain decisions will have to be made about how to deal with this. In this case the GUI or client sends out requests/tasks to the border router. The border node then responds after x time. In both cases this triggers a callback function on the receiving end, so that the data can be handled accordingly, see the image below.
+
+![img](img/fig-AsyncCommunication.svg)
## Communication standards
+
There are two options available, each has its own set of benefits listed in the table below.
<figure>
diff --git a/docs/fig.drawio b/docs/fig.drawio
index 0c6aa41..19a86e6 100644
--- a/docs/fig.drawio
+++ b/docs/fig.drawio
@@ -1 +1 @@
-<mxfile host="Electron" modified="2022-11-23T19:30:33.916Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/12.6.5 Chrome/80.0.3987.86 Electron/8.0.0 Safari/537.36" etag="j8_OhaWS9kVbTCn0c2AN" version="12.6.5" type="device" pages="2"><diagram id="TQBjHMX74tOWVntnVVwY" name="architecture">5VlRc5s4EP41nmkfkgFhbOcxdpxcO7lpWl/mro8CZKxaRj4hYru//lYgwCDskJg09VxeIq2EkL79dvcT7jmT1fZO4PXiTx4Q1kNWsO05Nz2EbAcN4J+y7DLLyNKGUNBATyoNM/qTaKOlrQkNSFyZKDlnkq6rRp9HEfFlxYaF4JvqtDln1beucUgMw8zHzLT+TQO50KdwrdL+B6HhIn+zbemRFc4na0O8wAHf7Jmcac+ZCM5l1lptJ4Qp8HJcsuduD4wWGxMkkm0eWF8Nf3xfTz9NfdcTmy+P5NtUXtijbJknzBJ9Yg9aADHsHg5BYvUvInLDxVKfQ+5ycARPooCo9e2eM94sqCSzNfbV6AboALaFXDE9jBkNI2gzMof9jhn2CHvgMZWUK7MPxyACBp6IkBQccF+b4HEp+WpvwrVeUHL1pjllbMIZhyVuIh7BHsaxFHxJcmMPOVb6ByMcdkmlouRQdbHwNfNQX3W9mLNEkuvCrPYf4HhRnFV1HrCEHUepBVnKarpEe0ltmWz3TNpFd4SviBQ7mJKParbsqt1NyT000LbFHu/gbJrzmu9hsXJJCWhoVryAIc7QYMj4r4IaNUKQAIJHd7mQCx7yCLNpaR2XlEn9UMy558qLKbY/iJQ7DTxOJK/SiETBtYrr0s1guaXqUOmShHnpYM6SuueOu/6gB2OeCJ8cwUmnNYlFSOSReRpOhdRRPgjCsKRP1TTUuXcHhnMjSOFHAt1qEehtoqmDUEG1UBmZsWLbDbHivlWo2Caav3WoHIuLhjDqLFSGLUPFbhkqmg8X1mUfjbQPWoePXu6BUzhGsVbfraXhGmeyveuHStoA3Hi3N22tJsSHXzOsvmZo1TiYrVd7Nl+cz+cxkb06awtgXk9kM+Wfb1aw3jsrwHHraE54NKdhInAqbZCVSMpU7KEBU9LIE9AKVetDOgwCeKlEjlK5qzWAJj6eJsVer71yEScy4A5osZqv6yX3HeUVGrWgh9NAj4Iz3VeNA8FmcAHejCyPiwBcBQmO/3+J0KD105OMsb8MUwDy0YDMcZIC2QF5bLdKHtQytRjVozvuuO+iK7ZU/qMev3R173suvqF9s93v7PLOM1qkM3HRbykuUEtx8TIh8VIBUNzbNKX6RxRAV9XdrEcs5ep5lPfaBblB9PcbQvDtrscGmF4CKTI6DzTtwe+FJjJr4bdbF4222/PE0zHxvPqVeNomPc2CYWTmPeCqKL8q8T9bjzpL/U7HqX/Pa+6RG8OJV017NLhE1XvgoMaH7OTGbdOsJv3B5WD/z6ksW5ewHV1iixTRWMNeOP3kkjcidvg0m6y+WqOh/TX892d/ctVQ8h5nY0UpIihm76KhntFDJ0SBa4ZBIyidK6DTCqlr+Cj3jrUGgLPb7yqJ4JaRXZvPoSAU6T4PwYYP+m/2OaLR6+Z10699jbh7/HSm4A5bgttFvW0E1znbVHIsQ/z6u9RJTjBF5OeLexote+pLmpeEofp+co78blCTXdEbuuUv0VnVLX/Pd6b/AQ==</diagram><diagram id="rUv2yiT5bNfH3vxD9CJS" name="demo">3VdNb9swDP01Pm7wB+Jm1yZZd8iAARnQ7ajarK1VMT1Fju3++tERHUc10DVLh6Q9WXymaOrxiZK9aLZubrQo86+YgvJCP228aO6FYRCFMT06pLXI1Gcg0zJlpwFYyUdg0Ge0kilsHEeDqIwsXTDBooDEOJjQGmvX7R6V+9VSZDACVolQY/RWpiZnNIg/DS++gMxy/vQ0vLIv1qJ35pVscpFifQBFCy+aaURjR+tmBqojr+clb33h423xezkN7rKrx/q7ePhgg30+Zsp+CRoK87qhpzb0VqiK+eK1mrYnEFLik03UJscMC6EWA3qtsSpS6D7jkzX4LBFLAgMCf4ExLYtDVAYJys1a8Vtalm5/dPM/TnrzJ4fbGfPGsVq2bK5dgk9q/Rei2G+DlU7gGT8mwwidwXPxor0aaBsBroGSpHkalDBy6yYnWM/Z3m8/9RtKSjv0ee9NWHe88YKp70awafGkofA0OMhigHZyOEZ1wXml4Ahh0MWFSyE+UQpOFY8tWTjazXPYEvAgSSGxoryv7zSNsm40U7KjZoSvammSfFx7pahldzWuc2lgVYodXzWdGm4Fxaa0ffxeNp0SuDRb0AaafyjOmMz6oI/7vCnygxa+B1+d4OgYglegadFjfLnL9IL55YZDh7+Ncz6+g4s6joIz96DJW+hBvWjOVLLAu6hj46UlO/UGcVLJJuOuhkVGhXlHZwZHCWP3UnUBPS5+Mftv9kB5Sv7/IJvM4VfM3oGHH9po8Qc=</diagram></mxfile> \ No newline at end of file
+<mxfile host="Electron" modified="2023-01-17T19:38:40.650Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.7.4 Chrome/106.0.5249.199 Electron/21.3.3 Safari/537.36" etag="vHeCIsdALQldInCo5Wv6" version="20.7.4" type="device" pages="3"><diagram id="TQBjHMX74tOWVntnVVwY" name="architecture">5VnRcps4FP0az7QPyYAA4zzGjpNtJztN683s9lGAjFUL5BUitvv1K4EAgzAhMWnq2Twk0pUQ0rnn3ntERtYs2t0xuFn9SQNERsAIdiPrZgSA49ritzTsc4PtuLkhZDjITWZlWOCfSBkNZU1xgJLaRE4p4XhTN/o0jpHPazbIGN3Wpy0pqb91A0OkGRY+JLr1bxzwVW6dOEZl/wPhcFW82TTUSASLycqQrGBAtwcmaz6yZoxSnrei3QwRiV2BS/7c7ZHRcmMMxbzPA5sr98f3zfzT3Hc8tv3yiL7N+YU5yZd5giRVJ/ZES0Asdi8OgRL5J0Z8S9lanYPvC3AYTeMAyfXNkTXdrjBHiw305ehWsEHYVjwiahgSHMaiTdBS7HdKoIfIA00wx1SafXEMxMTAE2IcCwfcNyZ4lHMaHUy4VgtyKt+0xITMKKFiiZuYxmIP04QzukaFcQQsI/sRI1TsEnNJSVd2IfMV84Atu15CScrRdWmW+w9gsirPKjsPkIsdx5kFGNKqu0R5SW4Z7Q5MykV3iEaIs72YUowqtuzr3W3FPTBWttUB78TZFOcV38Ny5YoSoqFY8QKGWK7GkOlfJTUahECBCB7VpYyvaEhjSOaVdVpRJvNDOeeeSi9m2P5AnO8V8DDltE4jFAfXMq4rNwvLLZaHypZExMsGC5Y0Pdft+qMeTGjKfNSB01glJ8hCxDvmKTglUp18YIhAjp/qaWhw744158Yig3cEutEj0PtE0wChAhqhMtFjxTRbYsV5q1AxdTR/61DpiouWMBosVNyeoWL2DBXFhwvj0gYT5YPe4aOWe6BYHKNcy3YaabjBmXzv6qGKNgJuuD+YtpETkuOvceuvcY0GB/P1Gs8Wi9PlMkF81GRtCczriayn/PPNCsZ7ZwVga2jOaLzEYcpgJm2AkXJMZOyBMZHSyGOiFcrWh2xYCOC1FDlS5UYbARr7eJoUe732KkQcy4E7osUavm6W3HeUV2DSgx5WCz1KzgxfNY4Em8YF8WZgeJQFwlUiwdH/LxFatH52kin012EGQDEaoCVMMyAHII/p1MkDeqYWrXoMxx3nXXTFDvN/5OOXjup9L8S3aN/sDjv7ovOMFhlMXNg9xQXoKS5eJiReKgDKe1vxeaRDAQxV3fV6RDKunkd5b1yQW0S/3RKCb3c91sD0UpEi4/NA0xz/XmgCvRZ+u3XAZLc7TzwtHc+rX4mnqdNTLxhaZj4Aro7yqxL/s/VosNRvDZz6D7zmdNwYTrxqmpPxJajfA8cNPuQn126bejWxx5fjwx+rtmxTwg50iS1TRGsNe+H0k0veBJnh02IWfTUmrvk1/PenPbtqKXmPi6mkFGIYknfRUM/ooROiwNHDoBWUwRXQaYXU0XxUeMfYCIDz22+UxuKWkV+bz6EglOm+CMGWD/pv9jmi1ev6ddNvfI24e/x0puC6PcEdot62gmudbSrpyhC//i51khN0Efn54h7H65H8kualYSi/n5wjv1vU5FD0Ft3qP9F51a3+nW/N/wM=</diagram><diagram id="rUv2yiT5bNfH3vxD9CJS" name="demo">3VdNb9swDP01Pm7wB+Jm1yZZd8iAARnQ7ajarK1VMT1Fju3++tERHUc10DVLh6Q9WXymaOrxiZK9aLZubrQo86+YgvJCP228aO6FYRCFMT06pLXI1Gcg0zJlpwFYyUdg0Ge0kilsHEeDqIwsXTDBooDEOJjQGmvX7R6V+9VSZDACVolQY/RWpiZnNIg/DS++gMxy/vQ0vLIv1qJ35pVscpFifQBFCy+aaURjR+tmBqojr+clb33h423xezkN7rKrx/q7ePhgg30+Zsp+CRoK87qhpzb0VqiK+eK1mrYnEFLik03UJscMC6EWA3qtsSpS6D7jkzX4LBFLAgMCf4ExLYtDVAYJys1a8Vtalm5/dPM/TnrzJ4fbGfPGsVq2bK5dgk9q/Rei2G+DlU7gGT8mwwidwXPxor0aaBsBroGSpHkalDBy6yYnWM/Z3m8/9RtKSjv0ee9NWHe88YKp70awafGkofA0OMhigHZyOEZ1wXml4Ahh0MWFSyE+UQpOFY8tWTjazXPYEvAgSSGxoryv7zSNsm40U7KjZoSvammSfFx7pahldzWuc2lgVYodXzWdGm4Fxaa0ffxeNp0SuDRb0AaafyjOmMz6oI/7vCnygxa+B1+d4OgYglegadFjfLnL9IL55YZDh7+Ncz6+g4s6joIz96DJW+hBvWjOVLLAu6hj46UlO/UGcVLJJuOuhkVGhXlHZwZHCWP3UnUBPS5+Mftv9kB5Sv7/IJvM4VfM3oGHH9po8Qc=</diagram><diagram id="zfEZus7OmDisMN2gApZM" name="protocol">5ZjRbtowFIafJtJ2UWQnBMIlsHabtknVqmmXk0tOE68mjhzTwp5+J9ghCYZRWIG14wLZv+1j55yP34AXjKfz94rl6RcZg/B8Es+94J3n+91+hO+lsDBCEFEjJIrHRmoIN/wXWJFYdcZjKFoTtZRC87wtTmSWwUS3NKaUfGxPu5OivWvOEnCEmwkTrvqdxzo1ahSSWv8APEmrnSmxI1NWTbZCkbJYPjak4NILxkpKbVrT+RhEmbsqL2bd1ZbR1cEUZPopC35ItUjVR7j61LuIZPiteODhhY3ywMTMPvBY8DKgObJeVHnA0+dlczYVn/kdCJ5hb5SD4lPQoHBEWPm61kZYFc1QK8fpsi8Eywt+uwxLUFEwmamCP8BXKEzxl6qcZTHEtrfK3LKjlbxf1aIMatf55ah9HFAa5lvzRFfZR2pB4mHVAqc81vXt2ZqljdIGVWWZRSpZLa2zjg2b+D2K4DtFuAGFz/A/FqFa0LfJPltRAqcoXjjqeSG2iIIil1kB2HyTAX5YyE/JM8/HnYi8f+vUrUwFR08ZCp5kKN1KreUUMwVZPCxNCjWZAw6NYlaky5xTM2wdMdpdAbMrxI6freUcTyZnagK7gdRMJaB3uYdbQwWCaaSpbcYbCmSXXmPydF37MDQr7I3hB7QzaL7a8cwhbYim/a1Fxbj7hDU5csJitdiiMS0vJxTbn4V2SXvXfsuksWEi1pyu8ng4ut1N6PoG3SauB1B6K+Tk/qQsVpf+Lhb9U7AYkQ5pvCg9DTT+CaAJN0HTLaEZ+96Q5DxLXggxZ3avQWeA3w/7tGveu22C6PqFtYUZ17+CQWdHqC1WuDd+vTZ+p7Cs3ib6iHvbGgxfyz17Zm/7M6n+E/F6AqlOqCMZ5eAEpPY3kUoNqcnycs3wN/ALscp/G0D6bFbphHouq1wDsOoflcBoE4Gh65VNGl+LY573bj/8Dj7W14S9gQ3XgP27yx279R9YZnr9L2Bw+Rs=</diagram></mxfile> \ No newline at end of file
diff --git a/docs/img/fig-AsyncCommunication.svg b/docs/img/fig-AsyncCommunication.svg
new file mode 100644
index 0000000..f04034a
--- /dev/null
+++ b/docs/img/fig-AsyncCommunication.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:lucid="lucid" width="463.25" height="446"><g transform="translate(-385.1250000000001 -300)" lucid:page-tab-id="0_0"><path d="M405.13 325a5 5 0 0 1 5-5h150a5 5 0 0 1 5 5v60a5 5 0 0 1-5 5h-150a5 5 0 0 1-5-5z" stroke="#000" stroke-opacity="0" fill="#a5ceff"/><use xlink:href="#a" transform="matrix(1,0,0,1,410.1250000000001,325) translate(59.025 33.15)"/><path d="M668.38 325a5 5 0 0 1 5-5h150a5 5 0 0 1 5 5v60a5 5 0 0 1-5 5h-150a5 5 0 0 1-5-5z" stroke="#000" stroke-opacity="0" fill="#a5ceff"/><use xlink:href="#b" transform="matrix(1,0,0,1,673.3750000000001,325) translate(58.05 33.15)"/><path d="M465.13 445a5 5 0 0 1 5-5h30a5 5 0 0 1 5 5v70a5 5 0 0 1-5 5h-30a5 5 0 0 1-5-5z" stroke="#000" stroke-opacity="0" fill="#d6d6d6"/><path d="M485.13 390.5v32.12" stroke="#333" fill="none"/><path d="M485.63 390.5h-1v-.5h1z" stroke="#333" stroke-width=".05" fill="#333"/><path d="M485.13 437.38l-4.64-14.26h9.26z" stroke="#333" fill="#333"/><path d="M728.13 445a5 5 0 0 1 5-5h30a5 5 0 0 1 5 5v210a5 5 0 0 1-5 5h-30a5 5 0 0 1-5-5z" stroke="#000" stroke-opacity="0" fill="#d6d6d6"/><path d="M748.38 390.5v32.12" stroke="#333" fill="none"/><path d="M748.88 390.5h-1v-.5h1z" stroke="#333" stroke-width=".05" fill="#333"/><path d="M748.38 437.38l-4.64-14.26H753z" stroke="#333" fill="#333"/><path d="M505.63 455.7H727.6" stroke="#333" fill="none"/><path d="M505.64 456.2h-.5v-1h.5z" stroke="#333" stroke-width=".05" fill="#333"/><path d="M709.8 445.02l18.07 10.7" stroke="#333" fill="none"/><use xlink:href="#c" transform="matrix(1,0,0,1,586.6499295526492,430.11435348204594) translate(0 14.4)"/><path d="M485.13 520.5v2.03m0 4.05v4.06m0 4.05v4.05m0 4.06v4.06m0 4.06v4.05m0 4.06v4.05m0 4.06v4.05m0 4.05v4.06m0 4.06v4.06m0 4.05v4.06m0 4.05v4.06m0 4.05v4.05m0 4.06v4.06m0 4.06v4.05m0 4.06v4.05m0 4.06v4.05m0 4.05v4.06m0 4.06v4.06m0 4.05v4.06m0 4.05v4.06m0 4.05v4.05m0 4.06v4.06m0 4.06v4.05m0 4.06v4.05m0 4.06v4.05m0 4.05v4.06m0 4.06v4.06m0 4.05v2.03" stroke="#333" fill="none"/><path d="M485.63 520.5h-1v-.5h1z" stroke="#333" stroke-width=".05" fill="#333"/><path d="M485.13 739.5v.5M727.63 580.48H506.1" stroke="#333" fill="none"/><path d="M728.13 580.98h-.52v-1h.52z" stroke="#333" stroke-width=".05" fill="#333"/><path d="M524.18 569.8l-18.07 10.68 18.08 10.7" stroke="#333" fill="none"/><use xlink:href="#d" transform="matrix(1,0,0,1,579.6499094842635,554.876263986471) translate(0 14.4)"/><path d="M465.13 575a5 5 0 0 1 5-5h30a5 5 0 0 1 5 5v70a5 5 0 0 1-5 5h-30a5 5 0 0 1-5-5z" stroke="#000" stroke-opacity="0" fill="#d6d6d6"/><path d="M748.13 660.5v1.98m0 3.94v3.96m0 3.95v3.94m0 3.96v3.94m0 3.96v3.95m0 3.94V702m0 3.94v3.96m0 3.95v3.94m0 3.96v3.94m0 3.96v3.95m0 3.94v1.98" stroke="#333" fill="none"/><path d="M748.63 660.5h-1v-.5h1z" stroke="#333" stroke-width=".05" fill="#333"/><path d="M748.13 739.5v.5" stroke="#333" fill="none"/><defs><path fill="#333" d="M143 4C61 4 22-44 18-125c-5-107 100-154 193-111 17 8 29 25 37 43l-32 9c-13-25-37-40-76-40-61 0-88 39-88 99 0 61 29 100 91 101 35 0 62-11 79-27v-45h-74v-28h105v86C228-13 192 4 143 4" id="e"/><path fill="#333" d="M232-93c-1 65-40 97-104 97C67 4 28-28 28-90v-158h33c8 89-33 224 67 224 102 0 64-133 71-224h33v155" id="f"/><path fill="#333" d="M33 0v-248h34V0H33" id="g"/><g id="a"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#e"/><use transform="matrix(0.05,0,0,0.05,14,0)" xlink:href="#f"/><use transform="matrix(0.05,0,0,0.05,26.950000000000003,0)" xlink:href="#g"/><path fill="#333" d="M-.9 1.25h33.75v1.32H-.9z"/></g><path fill="#333" d="M117-194c89-4 53 116 60 194h-32v-121c0-31-8-49-39-48C34-167 62-67 57 0H25l-1-190h30c1 10-1 24 2 32 11-22 29-35 61-36" id="h"/><path fill="#333" d="M233-177c-1 41-23 64-60 70L243 0h-38l-65-103H63V0H30v-248c88 3 205-21 203 71zM63-129c60-2 137 13 137-47 0-61-80-42-137-45v92" id="i"/><path fill="#333" d="M63-220v92h138v28H63V0H30v-248h175v28H63" id="j"/><g id="b"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#h"/><use transform="matrix(0.05,0,0,0.05,10,0)" xlink:href="#i"/><use transform="matrix(0.05,0,0,0.05,22.950000000000003,0)" xlink:href="#j"/><path fill="#333" d="M-.9 1.25h35.7v1.32H-.9z"/></g><path fill="#333" d="M114-163C36-179 61-72 57 0H25l-1-190h30c1 12-1 29 2 39 6-27 23-49 58-41v29" id="k"/><path fill="#333" d="M100-194c63 0 86 42 84 106H49c0 40 14 67 53 68 26 1 43-12 49-29l28 8c-11 28-37 45-77 45C44 4 14-33 15-96c1-61 26-98 85-98zm52 81c6-60-76-77-97-28-3 7-6 17-6 28h103" id="l"/><path fill="#333" d="M145-31C134-9 116 4 85 4 32 4 16-35 15-94c0-59 17-99 70-100 32-1 48 14 60 33 0-11-1-24 2-32h30l-1 268h-32zM93-21c41 0 51-33 51-76s-8-73-50-73c-40 0-46 35-46 75s5 74 45 74" id="m"/><path fill="#333" d="M84 4C-5 8 30-112 23-190h32v120c0 31 7 50 39 49 72-2 45-101 50-169h31l1 190h-30c-1-10 1-25-2-33-11 22-28 36-60 37" id="n"/><path fill="#333" d="M135-143c-3-34-86-38-87 0 15 53 115 12 119 90S17 21 10-45l28-5c4 36 97 45 98 0-10-56-113-15-118-90-4-57 82-63 122-42 12 7 21 19 24 35" id="o"/><path fill="#333" d="M59-47c-2 24 18 29 38 22v24C64 9 27 4 27-40v-127H5v-23h24l9-43h21v43h35v23H59v120" id="p"/><g id="c"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#k"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#l"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#m"/><use transform="matrix(0.05,0,0,0.05,25.950000000000003,0)" xlink:href="#n"/><use transform="matrix(0.05,0,0,0.05,35.95,0)" xlink:href="#l"/><use transform="matrix(0.05,0,0,0.05,45.95,0)" xlink:href="#o"/><use transform="matrix(0.05,0,0,0.05,54.95,0)" xlink:href="#p"/></g><path fill="#333" d="M115-194c55 1 70 41 70 98S169 2 115 4C84 4 66-9 55-30l1 105H24l-1-265h31l2 30c10-21 28-34 59-34zm-8 174c40 0 45-34 45-75s-6-73-45-74c-42 0-51 32-51 76 0 43 10 73 51 73" id="q"/><path fill="#333" d="M100-194c62-1 85 37 85 99 1 63-27 99-86 99S16-35 15-95c0-66 28-99 85-99zM99-20c44 1 53-31 53-75 0-43-8-75-51-75s-53 32-53 75 10 74 51 75" id="r"/><g id="d"><use transform="matrix(0.05,0,0,0.05,0,0)" xlink:href="#k"/><use transform="matrix(0.05,0,0,0.05,5.95,0)" xlink:href="#l"/><use transform="matrix(0.05,0,0,0.05,15.949999999999998,0)" xlink:href="#o"/><use transform="matrix(0.05,0,0,0.05,24.95,0)" xlink:href="#q"/><use transform="matrix(0.05,0,0,0.05,34.95,0)" xlink:href="#r"/><use transform="matrix(0.05,0,0,0.05,44.95,0)" xlink:href="#h"/><use transform="matrix(0.05,0,0,0.05,54.95,0)" xlink:href="#o"/><use transform="matrix(0.05,0,0,0.05,63.95,0)" xlink:href="#l"/></g></defs></g></svg> \ No newline at end of file
diff --git a/docs/img/fig-protocol.svg b/docs/img/fig-protocol.svg
new file mode 100644
index 0000000..485656e
--- /dev/null
+++ b/docs/img/fig-protocol.svg
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="232px" height="301px" viewBox="-0.5 -0.5 232 301"><defs/><g><rect x="0" y="0" width="60" height="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 30 20 L 30 300" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="29.5" y="14.5">Client</text></g><rect x="170" y="0" width="60" height="20" fill="rgb(255, 255, 255)" stroke="rgb(0, 0, 0)" pointer-events="all"/><path d="M 200 20 L 200 300" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="12px"><text x="199.5" y="14.5">Server</text></g><path d="M 199.5 270 L 150 270 Q 140 270 130 270 L 31.9 270" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 39.78 265.5 L 30.78 270 L 39.78 274.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="11px"><rect fill="rgb(255, 255, 255)" stroke="none" x="52" y="255" width="126" height="14" stroke-width="0"/><text x="114" y="264.5">[6] response (net join, ok)</text></g><path d="M 29.67 220 L 130 220 Q 140 220 150 220 L 191.38 220" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 198.38 220 L 191.38 223.5 L 191.38 216.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="11px"><rect fill="rgb(255, 255, 255)" stroke="none" x="89" y="205" width="53" height="14" stroke-width="0"/><text x="114.17" y="214.5">[2] net join</text></g><path d="M 199.5 70 L 170 70 Q 160 70 150 70 L 37.78 70" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 30.78 70 L 37.78 66.5 L 37.78 73.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="11px"><rect fill="rgb(255, 255, 255)" stroke="none" x="96" y="54" width="38" height="14" stroke-width="0"/><text x="114" y="64.5">[4] ping</text></g><path d="M 29.67 90 L 130 90 Q 140 90 150 90 L 197.26 90" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 189.38 94.5 L 198.38 90 L 189.38 85.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="11px"><rect fill="rgb(255, 255, 255)" stroke="none" x="60" y="74" width="111" height="14" stroke-width="0"/><text x="114.17" y="84.5">[0] response (ping, ok)</text></g><path d="M 29.67 140 L 130 140 Q 140 140 150 140 L 191.38 140" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 198.38 140 L 191.38 143.5 L 191.38 136.5 Z" fill="rgb(0, 0, 0)" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="11px"><rect fill="rgb(255, 255, 255)" stroke="none" x="85" y="125" width="60" height="14" stroke-width="0"/><text x="114.17" y="134.5">[1] get node</text></g><path d="M 199.5 170 L 160 170 Q 150 170 140 170 L 31.9 170" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" stroke-dasharray="3 3" pointer-events="stroke"/><path d="M 39.78 165.5 L 30.78 170 L 39.78 174.5" fill="none" stroke="rgb(0, 0, 0)" stroke-miterlimit="10" pointer-events="all"/><g fill="rgb(0, 0, 0)" font-family="Helvetica" text-anchor="middle" font-size="11px"><rect fill="rgb(255, 255, 255)" stroke="none" x="49" y="155" width="133" height="14" stroke-width="0"/><text x="114" y="164.5">[5] response (get node, ok)</text></g></g></svg> \ No newline at end of file