Palm OS Communications Primer: Serial Manager
A PDA itself is nice toy, maybe even useful for some common tasks such as ToDo or MemoPad applications, but without an option to communicate the to outer world, it's just peace of metal. In this set of articles, we will try to cover the main available communication types that you can use in your own applications.
Serial Manager is simple in usage and its capabilities. The first thing I woild like to point out is that serial communications under Palm OS are synchronous. That keeps all the business really simple. All Serial Manager's API calls may be divided into several logical groups:
- Opening and Closing the Serial Port
- Status, DeviceInfo, and Configuration
- Sending and Receiving Data
Let's briefly consider all these function groups.
Group 1: Opening and Closing the Serial Port
As a starting point, you'll be required to open a serial port. Serial Manager API offers you several functions for this purpose:
Err SrmOpen(UInt32 port, UInt32 baud, UInt16 *newPortIdP) Err SrmExtOpen(UInt32 port, SrmOpenConfigType* configP, UInt16 configSize, UInt16 *newPortIdP) Err SrmExtOpenBackground(UInt32 port, SrmOpenConfigType* configP, UInt16 configSize, UInt16 *newPortIdP) Err SrmOpenBackground(UInt32 port, UInt32 baud, UInt16 *newPortIdP)
All of them take a port number (either logical port number or 4-character port name) and return the Port ID for usage with other functions. You also may initially configure opening port providing either baud rate or configuration data. You will find common port constants in Table 1:
Using 4-character constants for physical hardware port names (refer to SystemResources.h for details) is not a good practice because it may be not present on some devices. There are also several virtual ports, as shown in Table 2:
|sysFileCVirtIrComm||'ircm'||A virtual serial cable over an IrDA link using the IRComm protocol. It can only be used to talk to another IRComm device.|
|sysFileCVirtRfComm||'rfcm'||RFCOMM (Bluetooth) virtual port plug-in.|
|sysFileCBtConnectPanelHelper||'btcp'||Bluetooth Connection Panel helper application.|
You can open a serial port in two different modes: foreground and background. Background ports relinquish control when another task opens the port with the SrmOpen or SrmExtOpen call. It's not recommended to keep a serial port in open mode longer than really neccessary because it consumes battery power. Finally, after the port is not needed, you may close it by making a SrmClose call.
SerOpen calls may return serErrAlreadyOpen error. It means that some other application is using it at this time. A good practice is to notify the user and close the port with SerClose.
Group 2: Configuration and Status
This functional group includes the following calls:
Err SrmGetDeviceCount(UInt16 *numOfDevicesP) Err SrmGetDeviceInfo(UInt32 deviceID, DeviceInfoType *deviceInfoP) Err SrmGetStatus(UInt16 portId, UInt32 *statusFieldP, UInt16 *lineErrsP) Err SrmClearErr (UInt16 portId) Err SrmSetReceiveBuffer(UInt16 portId, void *bufP, UInt16 bufSize); Err SrmControl(UInt16 portId, UInt16 op, void *valueP, UInt16 *valueLenP) Err SrmCustomControl(UInt16 portId, UInt16 opCode, UInt32 creator, void* valueP, UInt16* valueLenP)
Here we will discuss only the SrmControl function. Through it, you can configure the serial port. The valueP parameter depends on the specified op code (see SrmCtlEnum for all possible values). The following sample code demonstrates a simple settings definition:
UInt32 dwFlags = srmSettingsFlagBitsPerChar8 | srmSettingsFlagStopBits1; UInt16 wValueSize = sizeof(dwFlags); SrmControl(srmCtlSetFlags, &dwFlags, wValueSize);
The SrmCustomControl call in turn gives you an opportunity to communicate to the virtual driver in response to the specific op codes. All the rest of the functions are trivial enough, so we will move to the next section.
Group 3: Sending and Receiving Data
A wide family of Send/Receive functions allows you to carry out data exchange in different ways. Actually, all functions in this group may be broken into several categories:
UInt32 SrmSend (UInt16 portId, const void *bufP, UInt32 count, Err *errP) Err SrmSendWait(UInt16 portId) Err SrmSendCheck(UInt16 portId, UInt32 *numBytesP) Err SrmSendFlush(UInt16 portId) UInt32 SrmReceive(UInt16 portId, void *rcvBufP, UInt32 count, Int32 timeout, Err *errP) Err SrmReceiveWait(UInt16 portId, UInt32 bytes, Int32 timeout) Err SrmReceiveCheck(UInt16 portId, UInt32 *numBytesP) Err SrmReceiveFlush(UInt16 portId, Int32 timeout) Err SrmReceiveWindowOpen(UInt16 portId, UInt8 **bufPP, UInt32 *sizeP); Err SrmReceiveWindowClose(UInt16 portId, UInt32 bytesPulled); Err SrmSetWakeupHandler(UInt16 portId, WakeupHandlerProcPtr procP, UInt32 refCon); Err SrmPrimeWakeupHandler(UInt16 portId, UInt16 minBytes);
First, you can bluntly use a Send/Receive buffer. In addition, if you need to check the input/output queue or wait for completion of the transmition, xxxCheck and xxxWait will fulfill your requirements. xxxFlush purges the FIFO transmit queue.