Book Contents Previous Chapter Next Chapter
This chapter describes low-level software that works directly with Magic Cap's hardware. Before reading this chapter, you should be familiar with Magic Cap's object runtime.
Magic Cap communicators have various hardware features that provide services including serial input-output, power management, and infrared sending and receiving. Most software packages use these services through high-level interfaces. For example, to send electronic mail, your package can create a telecard and put it in the out box. This approach lets Magic Cap handle the details of setting up the hardware, such as the modem, radio, or infrared transmitter, connecting to an electronic mail service or another communicator, and sending the telecard.
In some specialized cases, you may want to create a package that has more direct access to the hardware, avoiding the higher levels of abstraction provided by Magic Cap. For example, if you're creating a package that implements a communication protocol by reading and interpreting a stream of bytes, you will probably need direct access to the Magic Bus serial port.
Magic Cap uses objects called servers to provide low-level access to hardware services. Magic Cap servers provide many of the features of drivers on other systems. You can get direct access to hardware services by calling operations of the appropriate servers. For example, the modem is represented by an object of class Modem, which is a subclass of Server.
You should only use servers when you must have direct access to hardware services. Servers provide several advantages over using higher-level interfaces. In particular, servers allow greater control over the hardware, and servers often provide faster access than higher-level objects.
However, there are also drawbacks to using servers. Servers require you to take care of many details normally handled by higher-level interfaces. When you use servers directly, your package may interfere with normal functions usually provided by higher-level access. For example, if your package accesses the speaker directly, Magic Cap code that also uses the speaker may be disrupted. In addition, you might inadvertently make your package dependent on particular features that are not present in all Magic Cap implementations. For these reasons, you should avoid using servers directly except when absolutely necessary, instead taking advantage of higher-level access provided by Magic Cap.
Many server classes have just one instance, created by Magic Cap. That instance represents a particular part of the communicator's hardware and provides a software interface for using that hardware. See the Standard Servers section below for more information.
This section describes some of the basic features provided by Magic Cap in servers. This section also discusses some of the standard servers built into Magic Cap and some of the important subclasses of servers.
Magic Cap includes a set of built-in servers that handle various hardware features. You can use these servers to gain direct access to hardware features. You'll usually refer to the servers by their indexicals. In general, you can call operations of servers for input, output, or status. Remember that you should avoid using the servers for access unless you've determined that you can't provide your features through a higher-level interface. If you must use servers, try to limit your use to checking status only if possible.
Note that the same hardware feature is often represented by several different servers. For example, the Magic Bus connector is represented by serial servers and by Magic Bus servers. This allows each user of the hardware feature to choose an appropriate server for its use of the feature.
WARNING: Servers provide direct access to specific hardware features. Although these features are all present in the first commercial implementations of Magic Cap 1.0, they may be changed or removed in future implementations.
Not all built-in servers actually inherit from class Server. For example, the server that represents the option key is an object of class OptionButton, which does not inherit from Server.
The following table lists the standard servers in Magic Cap, their classes, and descriptions of their functions:
---------------------------------------------------------------------------------------------------- server indexical server class description ---------------------------------------------------------------------------------------------------- iAvailablePrinters ObjectList List of available printers iBackupBatteryServer BackupBatteryServer Low-level access to backup battery iCardSlot1 CardSlot Low-level access to PC card slot and card itself; also iCardSlot2 if two slots iConsumerIRServer ConsumerIRServer Infrared transmitter for consumer remote control iDisplayServer DisplayServer Low-level access to LCD screen iFaxServer FaxServer Low-level fax send access iLinkServer LinkServer Access to personal computer link via serial connection iMagicBeam MagicBeam Infrared transmitter-receiver for data iMagicBus MagicBus Magic Bus access iMainBatteryServer MainBatteryServer or Low-level access to main battery MotoBatteryServer iMicrophone ITTSoundIn or Built-in microphone MacMicrophone iModem SerialServer or MacModem Built-in modem iOptionButton OptionButton Low-level access to option keys iPhoneServer Phone or HayesPhone Wireline telephone iPower Power State-related power information iPowerButton PowerButton Low-level access to on-off switch iPowerSupply PowerSupply General low-level power access iSerialAServer SerialServer Serial port that modem is connected to Magic Cap Simulator only) iSerialBServer SerialServer Magic Bus port using dumb serial connection iSpeaker ITTSpeaker or MacSpeaker Built-in speaker ----------------------------------------------------------------------------------------------------
The most commonly used servers are iModem, which provides access to the communicator's modem, and iSerialBServer, which lets your packages use the Magic Bus port as a dumb serial channel. Because these servers are commonly used, they are described in more detail in the following section, Communication Servers.
Magic Cap provides streams as a way to control reading and writing data serially. Streams are implemented by mixin class Stream, which defines operations such as Open, Close, Read, and Write. Like Unix pipes, each stream can be connected to another stream, its target. When a stream reads or writes, the actor it is running on waits while the reading or writing takes place, while other actors can continue to run.
Many server classes inherit from class Stream to read and write serial data using the hardware they represent. In particular, Magic Cap defines class HardwareStream, an abstract subclass of server and stream. Magic Cap has many subclasses of hardware stream, such as CommunicationStream, which is described in the next section.
For more information on class Stream and its features, see the TimeMinder and Miscellany samples in CodeWarrior Magic.
Magic Cap includes communication servers that provide access to features such as the modem, serial port, and infrared transmitter-receiver. Class CommunicationStream is an abstract subclass of hardware stream which adds fields and operations that are useful specifically for communication hardware. Most servers that represent communication hardware are communication streams, including Modem and SerialServer.
Servers that are communication streams have various operations that you might call when using those servers. Most of the methods defined by class CommunicationStream for these operations are just simple shells - the actual work of implementing them is left to subclasses. For example, CommunicationStream defines Connect to simply set its state to kConnected. Subclasses such as Modem must override Connect to handle the details of connecting.
Magic Cap defines class Modem to represent modems. There are various subclasses of modem which support built-in and external modems attached to the communicator. You can access the currently active modem by using the indexical iModem.
To use the modem directly, you can call operations of iModem. To begin using the modem, call its OpenPort operation. OpenPort will make sure that the modem is available for use and that the communicator has enough power to use it. If not, or if some other error prevents opening the modem, Magic Cap throws an exception. OpenPort also opens the modem's stream for reading and writing.
After opening the modem, you can call ConnectToNumber to dial the modem and make a connection. To make sure the phone number is correct for the current location, you can call LocalizedWithCallingCard on the phone label that contains the number before calling ConnectToNumber. When you call ConnectToNumber, Magic Cap checks the modem's ListenToConnect attribute to determine whether the modem's connection attempt should be made audible through the speaker. When you call ConnectToNumber, Magic Cap performs all the steps necessary to make a data connection, including setting up the modem, determining the optimum data rate, and handling any errors that might occur while setting up the connection. ConnectToNumber supports data rates of 300, 1200, 2400, 9600, and 19200 bits per second, although the hardware may be limited to slower speeds.
If you want to connect the modem at 2400 bits per second, you can call Connect, which requires a transfer ticket with the desired phone number. If you call Connect, Magic Cap will make sure a dialing location is set up, then call LocalizedWithCallingCard on the phone number in the transfer ticket. See this book's Electronic Mail chapter for more information about transfer tickets.
If you simply want to dial the phone without setting up a data connection, you can call the modem's DialNumber operation.
Once you've connected, you can use the modem's stream capabilities to read and write information. You don't have to open the stream because it was opened by the OpenPort call. You can call Read to read a specified number of bytes from the modem into a buffer you provide, or ReadAll to read a number of bytes or throw an exception if the specified number of bytes can't be read. You can call ReadUntil to read data until a specified value or number of bytes has been read.
You can call Write to send data to the modem from a buffer you provide, or you can use WriteByte to send a single byte of data.
If you want to check whether any bytes have not yet been read from the modem to the buffer, you can call CountReadPending. Similarly, you can call CountWritePending to see if any bytes have not yet been written from the buffer to the modem.
If you want to be notified if the modem disconnects unexpectedly, you can call MonitorDCD after connecting. If the modem carrier is lost, Magic Cap calls CarrierChanged, which puts up an announcement and closes the stream. If you connect by calling Connect instead of ConnectToNumber, Magic Cap automatically sets up the carrier monitoring for you, so you shouldn't call MonitorDCD if you connect via the Connect operation.
When you're ready to end the data connection, call Disconnect to turn off the modem and reset the modem. After calling Disconnect, you should call Close to close the stream.
Magic Cap provides a straightforward technique for using the communicator's Magic Bus port as a serial port. In general, you simply open the port, read and write data, then close the port when finished. This section describes the process in greater detail and presents additional features of simple serial communication.
Magic Cap defines class SerialServer to represent serial ports available for input and output. SerialServer is a communication stream that supports using serial ports, such as the Magic Bus port, for dumb serial communication. You can access the Magic Bus port as a serial port by using the indexical iSerialBServer. Some implementations use iSerialAServer to refer to a second serial port.
To use the serial port, you can call operations of SerialServer using the object referred to by iSerialBServer. To begin using the serial port, call its OpenPort operation. OpenPort will make sure that the serial port is available for use and that the communicator has enough power to use it. If not, or if some other error prevents using the serial port, Magic Cap throws an exception. OpenPort also opens the serial port's stream for reading and writing.
After opening the serial port, you can call Read to read a specified number of bytes from the port into a buffer you provide. You can call ReadWithCallback to read data from the port while calling a given function after every byte is read.
You can call Write to send information to the serial port from a buffer you provide. You can use WriteWithCallback to write data to the port while calling a given function after every byte is written.
If you want to check whether any bytes have not yet been read from the serial port to the buffer, you can call CountReadPending. Similarly, you can call CountWritePending to see if any bytes have not yet been written from the buffer to the port.
You can check or modify the serial port's data format by using the serial server's SerialDataFormat attribute. This attribute sets the number of data bits, stop bits, and parity. You can use the FlowControl attribute to read or change the port's flow control settings. You can call SendBreak to send a break of any duration to the serial port.
When you're finished using the port, you can call ClosePort to reset the port and stop reading and writing data.
Magic Cap defines mixin class PowerAware for objects that use the communicator's power resources. You'll rarely need to create subclasses that inherit from class PowerAware. In general, you'll only need to inherit from class PowerAware if your class controls actions that must not be interrupted when the user turns the communicator off.
Although objects of classes that are power-aware are notified when the communicator turns on or off, your package shouldn't use PowerAware as a way to handle management of normal power on and off transitions. Instead, you should use the techniques described in the Power Off and On section of this book's Software Packages chapter.
If you create a power-aware object, you should add it to the list of such objects by calling RegisterPowerAware on iPower, the power server. You can also call RegisterPowerAware to remove an object from the list by passing false as the last parameter. After registering your power-aware object, Magic Cap will call it whenever certain power-related events occur, as described in the rest of this section.
When the communicator is about to shut off its main power, Magic Cap calls CanSleep on every power-aware object. If you create a power-aware subclass, you can override CanSleep to perform some action, such as asking the user to confirm that an operation will be interrupted, before allowing the communicator to shut off.
When the communicator's power state changes, Magic Cap calls PowerStateChanged on every registered power-aware object. Magic Cap passes a value in the newState parameter to indicate the state transition that has occurred:
/* values for newState parameter in PowerStateChanged */ #define kUnitPowerUp 1 /* Communicator has powered on and the screen is on */ #define kUnitPowerDown 2 /* Communicator is shutting down */ #define kUnitPowerGood 3 /* Main battery has gone into low power state */ #define kUnitPowerLow 4 /* Main battery is out; backup battery is being used*/
If you create a power-aware subclass, you can override PowerStateChanged to get notification when the communicator's power state changes. You can then perform some action when a particular power state transition occurs.
This section describes how to create and install servers.
Every Magic Cap communicator includes at least one PCMCIA expansion interface, also called the PC card slot. Most PC cards contain RAM or ROM, which Magic Cap generally treats as additional memory. PC cards can also contain peripherals, such as modems, pagers, hard disks, or other devices.
This section discusses the software needed to support a PC card peripheral. The information in this section is intended to familiarize you with the basic concepts of supporting PC card peripherals and to answer initial questions. Creating a PC card peripheral requires additional, specialized information available to supported developers.
Magic Cap defines class CardServer as an abstract mixin class that represents PC cards installed in slots. When you create a PC card peripheral, you'll define a subclass of card server and declare an object of the subclass in your instance definition file. If your card reads and writes data, you might also inherit from class Stream. For example, Magic Cap defines class MemoryServer, which inherits from both CardServer and Stream, to represent PC cards that contain just RAM or ROM.
Magic Cap calls the card server to handle events associated with the card. The card server implements all the methods and other functions necessary for providing the card's features, including any low-level drivers. The card's server is usually provided on the card itself, as described in the following section.
The first time a PC card peripheral is inserted, Magic Cap faces a bootstrapping problem: it must load and install the card's server, which is on the card itself. Once the server is installed, it can handle any interaction with the card, including future insertions. This problem is solved by configuring part of the card as a memory card, which allows the memory server to load the card's server.
Magic Cap maintains a list of classes that can act as card servers, referred to by iCardServers. The servers are listed by their class numbers. When the user inserts a PC card into the slot, Magic Cap calls CanHandleCard on the last server in its list of card servers. If the server determines that the card is of a type that it can handle, it signals by returning a server as the return value of CanHandleCard. Magic Cap then calls the server's CardInsertion operation. If CanHandleCard returns nilObject instead, Magic Cap tries the next server, moving through the list from last to first.
The only card server built into Magic Cap is the memory server, which handles RAM and ROM cards. In order for a card to be recognized by this card server, part of the card must be configured as a RAM or ROM card. This configuration allows the memory server to handle the card, and when Magic Cap calls CardInsertion, the memory server will read in the RAM or ROM on the card that contains its own custom card server.
When the card's own server is loaded into memory, Magic Cap installs its objects, as it would with any package. The card server should override its InstallInto operation to add itself to the list in iCardServers.
VERSION NOTE: Generally, you can install package objects by listing them as part of an install-receive pair in the software package. However, because card servers are referred to by class numbers and the install-receive feature cannot install class numbers, you can't install card servers this way. Instead, you must override InstallInto as described above.
After calling CardInsertion, Magic Cap again checks the list of card servers to see if any new items were added. If the CardInsertion loaded a custom card server, the server will have been added to the list of card servers. If Magic Cap finds any new servers in the list, it calls CanHandleCard on the last newly added item to see if the new server can handle the card, then calls CardInsertion again if the new server wants to handle the card. This completes the card bootstrap process: the new card server is loaded and its CardInsertion operation is called to handle the card.
Here is a summary of the steps that take place when a hypothetical fast modem card is inserted into a new Magic Cap communicator:
Note that this section only describes the process of installing the card server. The task of writing the driver software and hooking it into Magic Cap is complex and is not covered in this book.
When the user inserts a card, your server's CanHandleCard method must determine whether it can support the card. PC cards define signature data called tuples that identify particular kinds of cards. Your server can read tuples to identify the card. Magic Cap defines class CardSlot to provide access to tuples on the card and other low-level information about the slot.
Your server's CanHandleCard method can call the card slot's FirstTuple operation to read the first tuple of a particular type, then NextTuple to read additional tuples. Your server can then use the tuple information to identify the card and determine whether to support it.
Some cards contain a tuple specific to Magic Cap called the magic tuple. Your server can read this data by calling the card slot's ReadMagicTuple operation.
Class CardSlot defines other operations that provide information about the card and the slot itself. For more information about class CardSlot, see this chapter's Related Classes section.
Magic Cap defines class CardSlot to provide low-level access to PC card slots. Magic Cap creates one card slot object for each PC card slot. Indexical iCardSlots contains an object list of these card slots. You can call CardSlot operations to work directly with card slots.
You can determine if a card is inserted at least part-way in the slot by calling CardInsertionSwitchState. Call CardDetectState to find out if a card is fully seated in the slot. CardBatteryState returns a value that indicates the status of the card's battery, and CardLockswitchState indicates whether the card's write-protect switch is on. You can call CardReadyState to check whether the card is currently busy performing some action, such as reading or writing.
Magic Cap defines class PCCard to provide an interface between the storeroom and a PC card. When the user inserts a PC card with storage, the card server that handles the card creates an object of class PCCard to provide information for the storeroom. You probably won't call any operations of class PCCard. If you create a specialized kind of storage card, you might create a subclass of PCCard to provide its interface to the storeroom.
For more information, see the following topics in Magic Cap Class and Method Reference:
class Modem
operations and attributes:
CarrierChanged Connect ConnectToNumber DialNumber Disconnect ListenToConnect MonitorDCD OpenPort
class SerialServer
operations and attributes:
FlowControl SendBreak SerialDataFormat
class PowerAware
operations and attributes:
CanSleep PowerStateChanged
class Server
class CardServer
operations and attributes:
CanHandleCard CardInsertion
class Stream
operations and attributes:
Close CountReadPending CountWritePending Open Read ReadAll ReadUntil Write WriteByte
class HardwareStream
class CommunicationStream
operations and attributes:
ReadWithCallback WriteWithCallback
class MemoryServer
class CardSlot
operations and attributes:
CardBatteryState CardDetectState CardInsertionSwitchState CardLockswitchState CardReadyState FirstTuple NextTuple ReadMagicTuple
class PCCard
indexicals:
iAvailablePrinters iBackupBatteryServer iCardServers iCardSlot1 iCardSlot2 iConsumerIRServer iDisplayServer iFaxServer iLinkServer iMagicBeam iMagicBus iMainBatteryServer iMicrophone iModem iOptionButton iPhoneServer iPower iPowerButton iPowerSupply iSerialAServer iSerialBServer iSpeaker
Book Contents Previous Chapter Next Chapter