The Serial Link Protocol
The Serial Link Protocol (SLP) provides an efficient packet send and receive mechanism that is used by the Palm OS® Desktop software and Debugger. SLP provides robust error detection with CRC-16. SLP is a best-effort protocol; it does not guarantee packet delivery (packet delivery is left to the higher-level protocols). For enhanced error detection and implementation convenience of higher-level protocols, SLP specifies packet type, source, destination, and transaction ID information as an integral part of its data packet structure.
SLP Packet Structures
The following sections describe:
SLP Packet Format
Each SLP packet consists of a packet header, client data of variable size, and a packet footer, as shown in Figure 3.1.
Figure 3.1 Structure of a Serial Link Packet

- The packet header contains the packet signature, the destination socket ID, the source socket ID, packet type, client data size, transaction ID, and header checksum. The packet signature is composed of the three bytes 0xBE, 0xEF, 0xED, in that order. The header checksum is an 8-bit arithmetic checksum of the entire packet header, not including the checksum field itself.
- The client data is a variable-size block of binary data specified by the user and is not interpreted by the Serial Link Protocol.
- The packet footer consists of the CRC-16 value computed over the packet header and client data.
Packet Type Assignment
Packet type values in the range of 0x00 through 0x7F are reserved for use by the system software. The following packet type assignments are currently implemented:
Socket ID Assignment
Socket IDs are divided into two categories: static and dynamic. The static socket IDs are "well-known" socket ID values that are reserved by the components of the system software. The dynamic socket IDs are assigned at runtime when requested by clients of SLP. Static socket ID values in the ranges 0x00 through 0x03 and 0xE0 through 0xFF are reserved for use by the system software. The following static socket IDs are currently implemented or reserved:
Transaction ID Assignment
Transaction ID values are not interpreted by the Serial Link Protocol and are for the sole benefit of the higher-level protocols. The following transaction ID values are currently reserved:
Transmitting an SLP Packet
This section provides an overview of the steps involved in transmitting an SLP packet. The next section describes the implementation.
Transmission of an SLP packet consists of these steps:
- Fill in the packet header and compute its checksum.
- Compute the CRC-16 of the packet header and client data.
- Transmit the packet header, client data, and packet footer.
- Return an error code to the client.
Receiving an SLP Packet
Receiving an SLP packet consists of these steps:
- Scan the serial input until the packet header signature is matched.
- Read in the rest of the packet header and validate its checksum.
- Read in the client data.
- Read in the packet footer and validate the packet CRC.
- Dispatch/return an error code and the packet (if successful) to the client.
The Serial Link Manager
The Serial Link Manager is the Palm OS implementation of the Serial Link Protocol.
The Serial Link Manager provides the mechanisms for managing multiple client sockets, sending packets, and receiving packets both synchronously and asynchronously. It also provides support for the Remote Debugger and Remote Procedure Calls (RPC).
Using the Serial Link Manager
Before an application can use the services of the Serial Link Manager, the application must open the manager by calling SlkOpen()
. Success is indicated by error codes of 0 (zero) or slkErrAlreadyOpen
. The return value slkErrAlreadyOpen
indicates that the Serial Link Manager has already been opened (most likely by another task). Other error codes indicate failure.
When you finish using the Serial Link Manager, call SlkClose()
. SlkClose
may be called only if SlkOpen()
returned 0 (zero) or slkErrAlreadyOpen
. When the open count reaches zero, SlkClose()
frees resources allocated by SlkOpen()
.
To use the Serial Link Manager socket services, open a Serial Link socket by calling SlkOpenSocket()
. Pass a reference number or port ID (for the Serial Manager) of an opened and initialized communications library (see SlkClose()
), a pointer to a memory location for returning the socket ID, and a Boolean indicating whether the socket is static or dynamic. If a static socket is being opened, the memory location for the socket ID must contain the desired socket number. If opening a dynamic socket, the new socket ID is returned in the passed memory location. Sharing of sockets is not supported. Success is indicated by an error code of 0 (zero). For information about static and dynamic socket IDs, see "Socket ID Assignment".
When you have finished using a Serial Link socket, close it by calling SlkCloseSocket()
. This releases system resources allocated for this socket by the serial link manager.
To set the interbyte packet receive timeout for a particular socket, call SlkSocketSetTimeout()
.
To flush the receive stream for a particular socket, call SlkFlushSocket()
, passing the socket number and the interbyte timeout.
To register a socket listener for a particular socket, call SlkSetSocketListener()
, passing the socket number of an open socket and a pointer to the SlkSocketListenType
structure. Because the Serial Link Manager does not make a copy of the SlkSocketListenType
structure but instead saves the pointer passed to it, the structure may not be an automatic variable (that is, allocated on the stack). The SlkSocketListenType
structure may be a global variable in an application or a locked chunk allocated from the dynamic heap. The SlkSocketListenType
structure specifies pointers to the socket listener procedure and the data buffers for dispatching packets destined for this socket. Pointers to two buffers must be specified:
- Packet header buffer (size of
SlkPktHeaderType
). - Packet body buffer, which must be large enough for the largest expected client data size.
Both buffers can be application global variables or locked chunks allocated from the dynamic heap.
The socket listener procedure is called when a valid packet is received for the socket. Pointers to the packet header buffer and the packet body buffer are passed as parameters to the socket listener procedure. The Serial Link Manager does not free the SlkSocketListenType
structure or the buffers when the socket is closed; freeing them is the responsibility of the application. For this mechanism to function, some task needs to assume the responsibility to "drive" the Serial Link Manager receiver by periodically calling SlkReceivePacket()
.
To send a packet, call SlkSendPacket()
, passing a pointer to the packet header (SlkPktHeaderType
) and a pointer to an array of SlkWriteDataType
structures. SlkSendPacket()
stuffs the signature, client data size, and the checksum fields of the packet header. The caller must fill in all other packet header fields. If the transaction ID field is set to 0 (zero), the serial link manager automatically generates and stuffs a new non-zero transaction ID. The array of SlkWriteDataType
structures enables the caller to specify the client data part of the packet as a list of noncontiguous blocks. The end of list is indicated by an array element with the size
field set to 0 (zero). Listing 3.1 incorporates the processes described in this section.
Listing 3.1 Sending a Serial Link Packet
status_t err; //serial link packet header SlkPktHeaderType sendHdr; //serial link write data segments SlkWriteDataType writeList[2]; //packet body(example packet body) UInt8 body[20]; // Initialize packet body ... // Compose the packet header. Let Serial Link Manager // set the transId. sendHdr.dest = slkSocketDLP; sendHdr.src = slkSocketDLP; sendHdr.type = slkPktTypeSystem; sendHdr.transId = 0; // Specify packet body writeList[0].size = sizeof(body); //first data block size writeList[0].dataP = body; //first data block pointer writeList[1].size = 0; //no more data blocks // Send the packet err = SlkSendPacket( &sendHdr, writeList ); ... }
Listing 3.2 Generating a New Transaction ID
// // Example: Generating a new transaction ID given the // previous transaction ID. Can start with any seed value. // UInt8 NextTransactionID (UInt8 previousTransactionID) { UInt8 nextTransactionID; // Generate a new transaction id, avoid the // reserved values (0x00 and 0xFF) if ( previousTransactionID >= (UInt8)0xFE ) nextTransactionID = 1; // wrap around else nextTransactionID = previousTransactionID + 1; // increment return nextTransactionID; }
To receive a packet, call SlkReceivePacket()
. You may request a packet for the passed socket ID only, or for any open socket that does not have a socket listener. The parameters also specify buffers for the packet header and client data, and a timeout. The timeout indicates how long the receiver should wait for a packet to begin arriving before timing out. A timeout value of (-1) means "wait forever." If a packet is received for a socket with a registered socket listener, the packet is dispatched via its socket listener procedure.