This package implements a standard SLIP protocol, with two non-standard but optional features. The package is completely decoupled from the physical I/O layer, allowing the user to implement SLIP over any imaginable byte stream. This is accomplished by having the application register it's own read and write byte routines.
Normal design practice usually layers additional features like compression on top of a lower layer. These features were embedded in this implementation to save on the limited AVR resources available (RAM). This eliminates the need for additional copies of packet buffers. The non-standard features are however, optional and may be disabled.
AVR systems often communicate with other peripherals or even the desktop PC over a serial link. Even others communicate with the desktop through USB on a serial link. The serial link used however, is asynchronous.
The nature of an asynchronous serial link is that there is no concept of a packet start or end. A byte or byte sequence is transmitted freely when required but needs no special announcement (like a message header/trailer). Even if you devise your own custom format of a message, it is possible to confuse the receiver if some serial bytes get injected through noise.
SLIP is useful in the streaming context when you need to put boundaries around messages. In this way, instead of looking for special byte codes that announce a command or request (like the MIDI protocol does), you can arrange to have a clearly defined packet communicated. Once a packet is received, the packet can be inspected as a structured unit of data.
SLIP however is only a framing protocol. Your sending application transmits a "message" and SLIP arranges the byte stream to appear at the remote end as a framed "message". If the transmission medium had no noise and no signal loss, this would be a reliable transport. However, SLIP does not guarantee reliable transport.
Things can be improved slightly by applying a CRC16 value. This is a non-standard SLIP extension provided in this implementation. It does not correct spurious transmissions, but should be useful in identifying them. By using the CRC16 feature, the receiver has a fairly reliable indication that the message is intact. It will not however, indicate if completely garbled messages were lost.
The slip package makes use of the AVR CRC16 package. See [CRC16] for more information.
This slip implementation provides a simple optional compression option. It reduces a repeated sequence of bytes (like blanks) into a four byte sequence:
[ESC] [RPT] [Byte] [n]
sequence, where:
If the characters repeat 2-4 times, they are sent as normal. Otherwise the sequence is reduce to the four byte format above.
The compression option is not a standard SLIP protocol feature.
The following displays the public summary of the package's types and API:
with Interfaces; use Interfaces; package Slip is type Slip_Context is private; type Packet_Type is array(Unsigned_8 range <>) of Unsigned_8; for Packet_Type'Component_Size use 8; type Transmit_Proc is access procedure(Byte : in Unsigned_8); type Receive_Proc is access procedure(Byte : out Unsigned_8); -- Open a SLIP Context procedure Open(Context : in out Slip_Context; Receive : in Receive_Proc; Transmit : in Transmit_Proc; Compress : in Boolean := True; CRC16 : in Boolean := True); -- Transmit a SLIP Packet procedure Transmit(Context : in out Slip_Context; -- SLIP Context Packet : in Packet_Type); -- Packet to send -- Receive a SLIP Packet procedure Receive(Context : in out Slip_Context; -- SLIP Context Packet : out Packet_Type; -- Packet receiving buffer Length : out Unsigned_8; -- Received packet length Error : out Boolean); -- False, when received ok function Error_Reason(Context : Slip_Context) return Character; end Slip;
The Slip_Context object must be initialized by Slip.Open prior to any SLIP I/O. This object contains the references to your application's read and write byte procedures, and defines what optional extensions (if any) are to be used. Additionally, the error code is saved here to allow for multiple concurrent SLIP sessions.
type Slip_Context is private;
The Slip.Open routine must be called prior to any other SLIP activity. The following definitions are applicable:
type Slip_Context is private; type Transmit_Proc is access procedure(Byte : in Unsigned_8); type Receive_Proc is access procedure(Byte : out Unsigned_8); procedure Open(Context : in out Slip_Context; Receive : in Receive_Proc; Transmit : in Transmit_Proc; Compress : in Boolean := True; CRC16 : in Boolean := True);
The caller must supply access pointers to these as required. If the link is only going to be reading, a Null value may be supplied for Transmit. If only transmitting is occurring, then supply Null for the Receive routine. Obviously if there is both transmitting and receiving going on, then you must supply both.
Supply True if you would like a simple repeat-count based link compression to be used. This is a non-standard extension and should only be used if the other end is also using the same slip package (or implementation). The argument defaults to True, so supply False if you require a standard SLIP interface.
The CRC16 argument, when supplied as True (or by default), will cause a CRC16 value to be appended to every SLIP packet transmitted (which must not be longer than 254 bytes). A CRC16 value will also be computed and checked for every packet received.
This is a not part of standard SLIP protocol, so you must supply False if you require a standard SLIP protocol. If the other end is also using the same slip package (or implementation), then it may be desirable to include this CRC16 check as an element of safety.
The Slip.Transmit procedure will cause the Unsigned_8 array (Packet_Type) to be transmitted as a packet, in SLIP protocol. Depending upon the Slip.Open call, there may also be a CRC16 value appended to the packet, and the packet data optionally compressed.
Control does not return until the last byte of the transmission has been accepted by the application's Write byte procedure.
procedure Transmit(Context : in out Slip_Context; -- SLIP Context Packet : in Packet_Type); -- Packet to send
The Slip.Receive procedure does not return until a packet has been received using the SLIP protocol. Depending upon how the Context was opened, it may include decompression and a CRC16 check. The packet length will be limited by the maximum length of the array supplied in argument Packet. The actual length of bytes returned is returned in argument Length.
If the packet is received successfully, the argument Error is set to False.
procedure Receive(Context : in out Slip_Context; -- SLIP Context Packet : out Packet_Type; -- Packet receiving buffer Length : out Unsigned_8; -- Received packet length Error : out Boolean); -- False, when received ok function Error_Reason(Context : Slip_Context) return Character;
When a packet error is received, it is sometimes useful to know what the nature of the error is. This is especially helpful in debugging a new SLIP link.
function Error_Reason(Context : Slip_Context) return Character;
The error code returned is one of the following characters:
The error code remains stable until the next Receive error encountered for the same Slip_Context object.
This indicates the packet being sent was too long for the receiving buffer (it was returned truncated) or that due to garbled data, it decompressed into a larger packet then it should be.
If the compression option is used, this indicates a protocol violation in the repeat count in the transmission. The data was either incorrectly formatted or garbled in the transmission.
This indicates that the data received violated the proper SLIP protocol. The received data, if any should be discarded.
The Slip_Context indicated that CRC16 is expected, but the transmission was too short to include a CRC16 value. This indicates a garbled transmission.
A CRC16 value was received but it did not match the one computed from the packet. The data received is suspect, and should be discarded.