Introduction to the SNAP protocol
Introduction
S.N.A.P. is a protocol for communication between several connected hosts. It provides:
· addressing
· flags
· ack/nak request
· error detection (different error detection methods available)
It can be run over different media, including RS485. It is optimized for a small footprint (limited computing, memory resources), but scaleable depending upon your needs.
Basically, if you want to connect several compute systems and the applications running on them, for instance a Raspberry Pi and several Atmel microcontrollers over their respective UARTs, using RS485 as media, you want something to wrap your data, deliver it to the correct hosts, receive acknowledgements that the data was received correctly, etc. This is what SNAP is for. It is in some ways an alternative to, for example, the Modbus protocol.
SNAP was developed by HTH, High Tech Horizon, a company from SWEDEN.
The homepage of the protocol is: http://www.hth.com/snap/
In order to communicate using the protocol you should get a vendor id, for which you can apply with HTH for free. They do ask you to include a PDF of the SNAP protocol, or a link to their web-site http://www.hth.com/snap/ with the applications/products. The vendor id is NOT included in the actual protocol bytes spoken in your application. You can therefore evaluate the protocol first, and then use the evaluation as actual implementation, no changes required.
Here is the list of currently registered vendor ids:
http://www.hth.com/snap/vidlist.html
Here is a link directly to the data sheet:
http://www.hth.com/filelibrary/pdffiles/snap.pdf
Some basic properties of SNAP
· binary protocol
· scaleable feature set, depending on your application
· works with synchronuous and asynchronuous communication (= e.g. UART)
· free for commercial and private use. Requires free vendor id for commercial id’s
The communication between the nodes is in the form of packets. Let’s discuss a sample packet, which uses some of the features of SNAP:
source: SNAP documentation, example of a simple SNAP packet
preamble: The preamble is optional, it can use any characters as long as they are not the synchronization byte, SYNC.
· SYNC: unique byte with the following structure: 01010100, indicates the start of the packet
· HDB2, HDB1: The header definition bytes HDB2 and HDB1 define how long the packet will be, and which features will be used.
· DAB1: Destination Address Byte
· SAB1: Source Address Byte
· DB1: Data Byte 1 – the payload for your application
· CRC2: high byte of CRC-16
· CRC1: low byte of CRC-16
address 0 is reserved as a broadcast address and should not be used for anything else. (DAB / SAB)
note: devices coming up in the middle of communications might synchronize on a “regular” 01010100 in the wrong position (where it was not meant as SYNC). Therefore a checksum should be used, so that the device can recognize that the data “does not fit”, and it should continue to listen for the next packet starting with the 01010100. (This is necessary to protect against frame shifts). Obviously the device will discard all bytes before it receives the first 01010100, as it did not get the full packet.
header definition bytes
SNAP is built in a modular and extensible way. You can define (DD) destination addresses with 0 – 3 bytes length in the DAB, destination address bytes. With a 3 bytes destination address (DD = 11) you will get up to 16 777 215 adressable nodes. With a 1 byte destination address (DD = 01), used in the example above, you will be able to address 255 addresses.
The same is true for the source address length (SS) in the source address bytes (SAB). In the example SS = 01 for 1 byte addresses.
PFB: protocol specific byte length. 0 – 3 bytes, as above (PP). In the example PP = 00. This feature is not yet implemented in SNAP, and therefore it should be set as 0, as in the example. A specialized implementation of SNAP could probably do something with them (e.g. packet counter, etc) – see SNAP documentation for some ideas.
ACK: this is an important area of the header definition. It indicates if the sending node requests an ACK / NAK packet in return, and also acts as the actual ACK / NAK response from the receiving node:
· 0 0 = No Ack request (Tx)
· 0 1 = Ack request (Tx)
· 1 0 = Ack response (Rx)
· 1 1 = NAK response (Rx)
CMD – command mode bit. Set this to zero, it’s an advanced feature of SNAP which you most likely will not use in your application.
EDM: error detection method. These three bits allow you to define the error detection method you would like to use. Read the SNAP documentation for details. In the example it was set as 1 0 0 = 16 bit CRC, adding two checksum bytes (CRC2, CRC1) at the tail of the packet.
NDB: four bits to determine how many data bytes there are in the packet.
1 byte, as in our example (one databyte: DB1) is set by 0 0 0 1
ACK / NAK
If you set the ACK to 00 in the Header definition byte 2 (HDB2), the transmitting node will not expect any ACK or NAK packet in return.
If you do send an ACK / NAK from the receiving node, in the example on page 23, the data byte is present with the same length (1 data byte) as in the sender’s original request, and filled with 0es.
The idea behind ACK / NAK is that the sending node can, after a time out, take appropriate action.
The data byte COULD be used for further information about the problem if a NAK is sent, this is outside of the SNAP specification.
Things you should think about
· how will the nodes determine their addresses?
for the master this is easy: it will receive a defined address. The slaves should get addresses in a predictable manner, so that it is repeatable. Ideally bound to some hardware characteristics.
· packet structure
Will you always use the same amount of data bytes? This will allow more deterministic timing, and easier implementation, etc.
· error detection
Which error detection algorithm should be chosen?
Please note that the SYNC byte is not included in the checksoum calculation.
CRC is capable of recognizing errors, and ideally even correct them (for a lower amount of errors).
page 14 of the protocol specification gives an overview of pre-calculated EDM checkvalues to test your own checksum implementation for the strings “SNAP” and “snap”.
· total packet length
HTH recommends to keep packets small (< 40 bytes) on medias like power line, RF or IR for improved performance.
· protocol specific flags (PFB)
These could be used in a specialized implementation of your protocol, allowing you to shift some application logic inside this, and to use the data as actual data. (e.g. the PFB bits could set what command you want the node to execute, and the data could be the required payload for the individual commands). or you could package command + data completely into the data, and just use SNAP for transport, addressing & ensuring that the package arrives without errors.
Python implementation
There is a Python implementation of SNAP available. Note this is for Python 2.
http://www.hth.com/snap/
Here’s a documentation for this module:
http://diyhpl.us/reprap/trunk/users/stef/pyRepRap/docs/reprap.snap.html
http://diyhpl.us/reprap/trunk/users/stef/pyRepRap/reprap/snap.py
Here is an example usage file:
http://diyhpl.us/reprap/trunk/users/stef/pyRepRap/examples/demo.py
Probably it’s more convenient to download the code here:
https://github.com/CarlosGS/Cyclone-PCB-Factory/tree/master/Software/PythonScripts/Replath/pyRepRap
This Python implementation implements a subset of SNAP for a certain application, but it is a good starting point for your own implementation.
Debugging tools & Library
http://www.hth.com/snap/snaplab.html
http://www.hth.com/snap/snaptest.html
These are a generic test application that is written in DELPHI and uses the COM port to communicate. Snaplab can spy on the SNAP network traffic, and generate SNAP packets with random data.
There is a C library for the SNAP protocol:
http://www.hth.com/snap/libdl.html
It does not implement the complete feature set of SNAP.
Here is a C++ implementation:
https://github.com/alx/reprap-arduino-firmware/blob/master/library/SNAP/SNAP.cpp