Documentation  |   Table of Contents   |  < Previous   |  Next >   |  Index

3    The Serial Link Protocol

Low-Level Communications

Exploring Palm OS®

The Serial Link Protocol ^TOP^

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 ^TOP^

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:

0x00

Remote Debugger, Remote Console, and System Remote Procedure Call packets.

0x02

PADP packets.

0x03

Loop-back test packets.

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:

0x00

Remote Debugger socket.

0x01

Remote Console socket.

0x02

Remote UI socket.

0x03

Desktop Link Server socket.

0x04–0xCF

Reserved for dynamic assignment.

0xD0–0xDF

Reserved for testing.

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:

0x00 and 0xFF

Reserved for use by the system software.

0x00

Reserved by the Palm OS implementation of SLP to request automatic transaction ID generation.

0xFF

Reserved for the connection manager's WakeUp packets.

Transmitting an SLP Packet ^TOP^

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:

  1. Fill in the packet header and compute its checksum.
  2. Compute the CRC-16 of the packet header and client data.
  3. Transmit the packet header, client data, and packet footer.
  4. Return an error code to the client.

Receiving an SLP Packet ^TOP^

Receiving an SLP packet consists of these steps:

  1. Scan the serial input until the packet header signature is matched.
  2. Read in the rest of the packet header and validate its checksum.
  3. Read in the client data.
  4. Read in the packet footer and validate the packet CRC.
  5. Dispatch/return an error code and the packet (if successful) to the client.

The Serial Link Manager ^TOP^

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 ^TOP^

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.