< Home < Developers < Development Support < Documentation

## 10 Palm System Support

Table of Contents | < Previous | Next > | Index

| Title - Palm OS® Programmer's Companion vol. I 10 Palm System Support Features The System Version Feature Application-Defined Features Using the Feature Manager Feature Memory Preferences Accessing System Preferences Setting System Preferences Setting Application-Specific Preferences Sound Synchronous and Asynchronous Sound Using the Sound Manager Sound Preferences Compatibility Information System Boot and Reset Soft Reset Soft Reset + Up Arrow Hard Reset System Reset Calls Hardware Interaction Palm OS Power Modes Guidelines for Application Developers Power Management Calls The Microkernel Retrieving the ROM Serial Number Time Using Real-Time Clock Functions Using System Ticks Functions Floating-Point Summary of System Features |  |  |  | In this chapter, you learn how to work with the miscellaneous supporting functionality that the Palm OS® system provides, such as sound, time, and floating-point operations. Most parts of the Palm OS are controlled by a manager, which is a group of functions that work together to implement a certain functionality. As a rule, all functions that belong to one manager use the same prefix and work together to implement a certain aspect of functionality. This chapter discusses these topics: Features Preferences Sound System Boot and Reset Hardware Interaction The Microkernel Retrieving the ROM Serial Number Time Floating-Point Summary of System Features ## Features A feature is a 32-bit value that has special meaning to both the feature publisher and to users of that feature. Features can be published by the system or by applications. Each feature is identified by a feature creator and a feature number: The feature creator is a unique creator registered with Palm, Inc. You usually use the creator type of the application that publishes the feature. The feature number is any 16-bit value used to distinguish between different features of a particular creator. Once a feature is published, it remains present until it is explicitly unregistered or the device is reset. A feature published by an application sticks around even after the application quits. This section introduces the feature manager by discussing these topics: The System Version Feature Application-Defined Features Using the Feature Manager Feature Memory ## The System Version Feature An example for a feature is the system version. This feature is published by the system and contains a 32-bit representation of the system version. The system version has a feature creator of sysFtrCreator and a feature number of sysFtrNumROMVersion). Currently, the different versions of the system software have the following numbers: #####
0x01003001 | Palm OS 1.0
0x02003000 | Palm OS 2.0
0x03003000 | Palm OS 3.0
0x03103000 | Palm OS 3.1
0x03203000 | Palm OS 3.2
0x03503000 | Palm OS 3.5
0x04003000 | Palm OS 4.0
Rather than hard wiring an obscure constant like one of the above into your code, however, you can use the sysMakeROMVersion macro (defined in SystemMgr.h) to construct a version number for comparison purposes. It takes five parameters: Major version number Minor version number Fix level Build stage (either sysROMStageDevelopment, sysROMStageAlpha, sysROMStageBeta, or sysROMStageRelease) Build number The fix level and build number parameters are normally set to zero, while build stage is usually set to sysROMStageRelease. Simply check to see whether sysFtrNumROMVersion is greater than or equal to the version number constructed with sysMakeROMVersion, as shown here:
    // See if we're on ROM version 3.1 or later.
    FtrGet(sysFtrCreator, sysFtrNumROMVersion, &romVersion);
    if (romVersion >= sysMakeROMVersion(3, 1, 0,
        sysROMStageRelease, 0)) {
       ....
    }
Other system features are defined in SystemMgr.h. System features are stored in a feature table in the ROM. (In Palm OS 3.1 and higher, the contents of this table are copied into the RAM feature table at system startup.) Checking for the presence of system features allows an application to be compatible with multiple versions of the system by refining its behavior depending on which capabilities are present or not. Future hardware platforms may lack some capabilities present in the first platform, so checking the system version feature is important. IMPORTANT: For best results, we recommend that you check for specific features rather than relying on the system version number to determine if a specific API is available. For more details on checking for features, see the appendix Compatibility Guide in Palm OS Programmer's API Reference. ## Application-Defined Features Applications may find the feature manager useful for their own private use. For example, an application may want to publish a feature that contains a pointer to some private data it needs for processing launch codes. Because an application's global data is not generally available while it processes launch codes, using the feature manager is usually the easiest way for an application to get to its data. The feature manager maintains one feature table in the RAM as well as the feature table in the ROM. Application-defined features are stored in the RAM feature table. ## Using the Feature Manager To check whether a particular feature is present, call FtrGet and pass it the feature creator and feature number. If the feature exists, FtrGet returns the 32-bit value of the feature. If the feature doesn't exist, an error code is returned. To publish a new feature or change the value of an existing one, call FtrSet and pass the feature creator, number, and the 32-bit value of the feature. A published feature remains available until it is explicitly removed by a call to FtrUnregister or until the system resets; simply quitting an application doesn't remove a feature published by that application. Call FtrUnregister to remove features that were created by calling FtrSet. You can get a complete list of all published features by calling FtrGetByIndex repeatedly. Passing an index value starting at 0 to FtrGetByIndex and incrementing repeatedly by 1 eventually returns all available features. FtrGetByIndex accepts a parameter that specifies whether to search the ROM feature table or RAM feature table. Note that in Palm OS version 3.1 and higher, the contents of the ROM table are copied into the RAM table at system startup; thus the RAM table serves the entire system. ## Feature Memory Palm OS 3.1 adds support for feature memory. Feature memory provides quick, efficient access to data that persists between invocations of an application. The values stored in feature memory persist until the device is reset or until you explicitly free the memory. Feature memory is memory allocated from the storage heap. Thus, you write to feature memory using DmWrite, which means that writing to feature memory is no faster than writing to a database. However, feature memory can provide more efficient access to that data in certain circumstances. To allocate a chunk of feature memory, call FtrPtrNew, specifying a feature creator, a feature number, the number of bytes to allocate, and a location where the feature manager can return a pointer to the newly allocated memory chunk. For example:
    FtrPtrNew(appCreator,
        myFtrMemFtr, 32, &ftrMem);
Elsewhere in your application, you can obtain the pointer to the feature memory chunk using FtrGet. NOTE: Starting with Palm OS 3.5 FtrPtrNew allows allocating chunks larger than 64KB. Do keep in mind standard issues with allocating large chunks of memory: there might not be enough contiguous space, and it can impact system performance. Feature memory is considered a performance optimization. The conditions under which you'd use it are not common, and you probably won't find them in a typical application. You use feature memory in code that: Is executed infrequently Does not have access to global variables Needs access to data whose contents change infrequently and that cannot be stored in a 32-bit feature value For example, suppose you've written a function that is called in response to a launch code, and you expect to receive this launch code frequently. Suppose that function needs access to the application's preferences database. At the start of the function, you'd need to open the database and read the data from it. If the function is called frequently, opening the database each time can be a drain on performance. Instead, you can allocate a chunk of feature memory and write the values you need to that chunk. Because the chunk persists until the device is reset, you only need to open the database once. Listing 10.1 illustrates this example. Listing 10.1 Using feature memory
    MyAppPreferencesType prefs;

    if (FtrGet(appCreator, myPrefFtr, (UInt32*)&prefs) != 0) {

       // Feature memory doesn't exist, so allocate it.
       FtrPtrNew(appCreator, myPrefFtr, 32, &thePref);

       // Load the preferences database.
       PrefGetAppPreferences (appCreator, prefID, &prefs,
          sizeof(prefs), true);

       // Write it to feature memory.
       DmWrite(thePref, 0, &prefs, sizeof(prefs));
    }
    // Now prefs is guaranteed to be defined.
Another potential use of feature memory is to "publish" data from your application or library to other applications when that data doesn't fit in a normal 32-bit feature value. For example, suppose you are writing a communications library and you want to publish an icon that client applications can use to draw the current connection state. The library can use FtrPtrNew to allocate a feature memory chunk and store an icon representing the current state in that location. Applications can then use FtrGet to access the icon and pass the result to WinDrawBitmap to display the connection state on the screen. ## Preferences The Preferences Manager handles both system-wide preferences and application-specific preferences. The Preferences Manager maintains preferences in two separate databases: The "saved" preferences database contains preferences that are backed up during a HotSync operation. There is one "saved" preferences database that all applications use. This database contains all system-wide preferences as well as application-specific preferences. The "unsaved" preferences database contains application-specific preferences that are not to be backed up during a HotSync operation. There is one "unsaved" preferences database that all application use. This section describes how to obtain and set values for each of these preferences databases. It covers: Accessing System Preferences Setting System Preferences Setting Application-Specific Preferences ## Accessing System Preferences The system preferences specify how users want their Palm Powered handhelds to behave. For example, system preferences specify how dates and times are displayed and whether the system plays a sound when an alarm fires. These values are typically set using the built-in Preferences or Security application. Applications should, as a rule, respect the values stored in the system preferences. To obtain the value of a system preference, use the PrefGetPreference function and pass one of the SystemPreferencesChoice enum constants. For example, if an application's user interface displays the current date and time, it could do the following to find out how the user wants the date and time displayed:
    TimeFormatType timeFormat = (TimeFormatType)
       PrefGetPreference(prefTimeFormat);
    DateFormatType dateFormat = (DateFormatType)
       PrefGetPreference(prefDateFormat);
WARNING! Do not confuse PrefGetPreference with PrefGetPreferences. The latter function is obsolete and retrieves the 1.0 version of the system preferences structure. Note that the PrefGetPreference function by default returns a UInt32 value. This return value must be cast to the appropriate type for the preference being returned. Also note that the system preferences structure has been updated many times and maintains its own version information. Each Palm OS release that modifies the system preferences structure adds its new values to the end and increments the structure's version number. See Table 10.1. #####
Table 10.1 System preference version numbers
Palm OS Version | System Preference Version
--- | ---
2.0 | 2
3.0 | 3
3.0 | 4
3.1 | 5
3.2 | 6
3.3 | 7
3.5 | 8
4.0 | 9
To learn which preferences were added in which version, as well as the return type expected for each preference, see Table 44.1 in the Palm OS Programmer's API Reference. To maintain backward compatibility, check the preference version number before checking the value of any preference added after Palm OS 2.0. For example, Palm OS 4.0 added a preference that allows you to access the device's locale information (the country and language) as an LmLocaleType structure. Before you try to access that preference, you should check the preference version, as shown in Listing 10.2. Listing 10.2 Checking the system preference version
    LmLocaleType currentLocale;
    CountryType currentCountry;
    if (PrefGetPreference(prefVersion) >= preferenceDataVer9) {
       currentLocale = (LmLocaleType)
         PrefGetPreference(prefLocale);
    } else { /* make do with the country */
       currentCountry = (CountryType)
         PrefGetPreference(prefCountry);
    }
In some cases, a newer preference is intended to replace an existing preference. For example, the prefAutoOffDuration preference is replaced by prefAutoOffDurationSecs in version 8 of the preference structure. The older preference stored the auto-off time in minutes, and the newer one stores the time in seconds. If you use prefAutoOffDuration in Palm OS 4.0, the system still returns the current auto-off time in minutes; however, to obtain this value, the system converts the value in seconds to minutes and rounds the result if necessary. You'll receive a more precise value if you use prefAutoOffDurationSecs. ## Setting System Preferences Occasionally, an application may need to set the value of a system-wide preference. It is strongly recommended that you not override the system preferences without user input. For example, suppose you are writing a replacement for the built-in Address Book application. The Preferences application contains a panel where the user can remap the Address Book hard key to open any application they choose. However, you want to make it more convenient for your users to remap the Address Book button, so you might display an alert that asks first-time users if they want the button remapped. If they tap Yes, then you should call PrefSetPreference with the new value. The code might look like the following: Listing 10.3 Setting a system preference
    if (PrefGetPreference(prefHard2CharAppCreator !=
          myAppCreatorId)) {
       if (FrmAlert(MakeMeTheDefaultAlert) == 0) {
          /* user pressed Yes */
          PrefSetPreference(prefHard2CharAppCreator ,
             myAppCreatorId);
       }
    }
WARNING! Do not confuse PrefSetPreference with PrefSetPreferences. The latter function is obsolete and sets the entire system preferences structure for version 1.0. ## Setting Application-Specific Preferences You can use the Preferences Manager to set and retrieve preferences specific to your application. You do this by storing the preferences in one of two databases: the "saved" preferences database or the "unsaved" preferences database. To write application preferences, you use PrefSetAppPreferences. To read them back in, you use PrefGetAppPreferences. Typically, you write the preferences in response to the appStopEvent when control is about to pass to another application. You read the preferences in response to a normal launch. PrefSetAppPreferences and PrefGetAppPreferences take roughly the same parameters: the application creator ID, a preference ID that uniquely identifies this preference resource, a pointer to a structure that holds the preference values, the size of the preferences structure, and a Boolean that indicates whether the "saved" or the "unsaved" preferences database is to be used. PrefSetAppPreferences also takes a version number for the preference structure. This value is the return value for PrefGetAppPreferences. The following sections discuss the issues involved in using application-specific preferences: When to Use Application Preferences How to Store Preferences Which Preferences Database to Use Updating Preferences Upon a New Release #### When to Use Application Preferences You use application preferences to store state specific to your application that should persist across invocations of your application. For example, the built-in applications store information about the last form and the last record or records displayed before control switched to another application. This way, the user can be returned to the same view when he or she goes back to that application. You can also use preferences for other values. You might allow the user to customize the way the application behaves and store such information in the preferences database. You might also use the preferences database as a way to share information with other applications. Make sure that the preference values you choose are as concise as possible. In games, for example, it is often tempting to store a bitmap for the current state of the screen. Such a bitmap is over 25KB on a color device, and it is therefore best avoided. Instead, it is better to store items that let you recreate the current state, such as the player's position in pixels and the current level. There are other ways to store values pertinent to your application. For example, you can store a single value as a feature using the Feature Manager. The differences between storing application value as preferences and storing application values as features are: Preferences (including those stored in the "unsaved" database) survive a soft reset because they reside in the storage heap. Features are deleted upon a soft reset. For this reason, preferences are more appropriate for storing application state than feature are. An application preference is a database record, so it has a size limit of 64KB. Multiple application preferences are allowed. The features that are supported by all releases of Palm OS have a maximum size of 4KB. In Palm OS 3.1 and higher, you can create features greater than 4KB by using feature memory. Feature memory has a maximum size of 64KB before Palm OS 3.5. Palm OS 3.5 and higher allows allocating a chunk of feature memory that is larger than 64KB. However, feature memory is intended to be used in different situations than an application preference is. See the section "Feature Memory" for more information. Instead of storing application state values as preferences or features, you could also use a database that your application creates and maintains itself. If you choose this method of storing application preference values, you must write your own functions to read the preferences from the database and write the preferences to the database. If you want the preferences backed up, you need to set the backup bit. However, there may be cases where using your own database has advantages. See "Which Preferences Database to Use". #### How to Store Preferences Most applications store a single preference structure under a single preference resource ID. When the application receives an appStopEvent, it writes the entire structure to the resource using PrefSetAppPreferences. When it receives a sysAppLaunchCmdNormalLaunch, it reads the structure back in using PrefGetAppPreferences. Storing a single preference structure in the database is a convention that most applications follow because it is convenient to access the all preferences at once. The Preferences Manager does allow an application to store more than one preference resource. This requires more calls to PrefSetAppPreferences and PrefGetAppPreferences, but you may find it more convenient to use several preference resources if you have several variable-length preferences. #### Which Preferences Database to Use Both PrefGetAppPreferences and PrefSetAppPreferences take a Boolean value that indicates whether the value is to be read from and written to the "saved" or the "unsaved" preferences database. To write the preference to the "saved" preferences database, use true. To write to the "unsaved" preferences database, use false. The only difference between the two databases is that the "saved" preferences database is backed up when a user performs the HotSync operation, and the "unsaved" preferences database is not backed up by default. (The user can use a third-party tool to set the backup bit in the "unsaved" preferences database, which would cause it to be backed up.) Both the "saved" and the "unsaved" preferences reside in the storage heap and thus persist across soft resets. The only way that preferences are lost is if a hard reset is performed. Use the "saved" preferences only for items that must be restored after a hard reset, and use the "unsaved" preferences for the current state of the application. For example, if your application has a registration code, you might write that to the "saved" preferences database so that the user does not have to look up the registration code and re-enter it after a hard reset. However, such items as the current form being displayed and the current database record being displayed can be lost, so they are written to the "unsaved" preferences database. For games, you might write the high score to the "saved" preferences database and any information about the current game to the "unsaved" preferences database. It is important to use the "saved" preferences database sparingly. Any time that any application stores or changes a preference in the "saved" preferences database, the entire database is backed up during the next HotSync operation. For users with a large number of applications, this practice can seriously impact the time that it takes to perform a HotSync operation. Listing 10.4 shows the preferences structures and the StopApplication function from the HardBall application. The HardBallPreferenceType, which is written to the "saved" preferences database, only stores the high score information and accumulated time. All other preferences are stored in GameStatusType, which is written to the "unsaved" preferences database. Listing 10.4 Saving application-specific preferences
    typedef struct {
       SavedScore highScore[highScoreMax];
       UInt8 lastHighScore;
       UInt8 startLevel;
       UInt32  accumulatedTime;
    } HardBallPreferenceType;

    typedef struct {
       enum gameProgress  status;
       UInt8  periodLength;
       UInt32 nextPeriodTime;
       UInt32 periodsToWait;
       Boolean  paused;
       UInt32  pausedTime;
       BrickType  brick[rowsOfBricks][columnsOfBricks];
       UInt8  bricksRemaining;
       UInt8 level;
       WorldState last;
       WorldState next;
       RemovedBrick brokenBricks[brokenBricksMax];
       Int16  brokenBricksCount;
       UInt8 ballsRemaining;
       Boolean movePaddleLeft;
       Boolean movePaddleRight;
       SoundType  soundToMake;
       Int8  soundPeriodsRemaining;
       Int32  scoreToAwardBonusBall;
       Boolean lowestHighScorePassed;
       Boolean highestHighScorePassed;
       Boolean gameSpedUp;
       Boolean  cheatMode;
       UInt32 startTime;
    } GameStatusType;

    HardBallPreferenceType Prefs;
    static GameStatusType GameStatus;

    static void StopApplication (void)
    {
       ...
       // Update the time accounting.
       Prefs.accumulatedTime += (TimGetTicks() -
          GameStatus.startTime);

       // If we are saving a game resuming (it hasn't started
       // playing yet) then preserve the game status.
       if (GameStatus.status == gameResuming) {
          GameStatus.status = SavedGameStatus;
       }

       // Save state/prefs.
       PrefSetAppPreferences (appFileCreator, appPrefID,
          appPrefVersion, &Prefs, sizeof (Prefs), true);

       PrefSetAppPreferences (appFileCreator, appSavedGameID,
          appSavedGameVersion, &GameStatus, sizeof (GameStatus),
          false);

       // Close all the open forms.
       FrmCloseAllForms ();
    }
If you have a large amount of preference data that must be backed up during a HotSync operation and is frequently changed, you could, as a performance optimization, store the preferences in a database that your own application creates and maintains rather than in the "saved" preferences database. This saves the user from having to have the entire "saved" preferences database backed up on every HotSync operation. The disadvantage of this method of saving application preferences is that you must write all code to maintain the database and to retrieve information from it. #### Updating Preferences Upon a New Release When you update your application, you may have new items that you want to store in the preferences database. You may choose to write a separate preference record to the database. However, it is better to update the current preference structure, size permitting. The PrefSetAppPreferences and PrefGetAppPreferences functions use a versioning system that allows you to update an existing preference structure. To use it, keep track of the version number that you pass to PrefSetAppPreferences. Add any new preferences to the end of the preferences structure, and then increment the version number. You might use a macro for this purpose:
    #define CurrentPrefsVersion 2
When a user launches the new version of the application, PrefGetAppPreferences is called before PrefSetAppPreferences. The PrefGetAppPreferences function returns the version number of the preference structure that it retrieved from the database. For example, if the new version is version 2, PrefGetAppPreferences returns 1 the first time that version 2 is run. If the returned version does not match the current version, you know that the user does not have values for the new preferences introduced in version 2. You can then decide to provide default values for those new preferences. The first time any version of your application is run, PrefGetAppPreferences returns noPreferenceFound. This indicates that the user does not have any preferences for the current application and the application must supply default values for the entire preferences structure. Listing 10.5 shows how the Datebook handles retrieving the version number from PrefGetAppPreferences. Listing 10.5 Checking the preference version number
    #define datebookPrefsVersionNum 4

    Int16 DatebookLoadPrefs (DatebookPreferenceType* prefsP)
    {
       UInt16 prefsSize;
       Int16 prefsVersion = noPreferenceFound;
       Boolean haveDefaultFont = false;
       UInt32 defaultFont;

       ErrNonFatalDisplayIf(!prefsP, "null prefP arg");

       // Read the preferences / saved-state information.  Fix-up if no prefs or
       // older/newer version
       prefsSize = sizeof (DatebookPreferenceType);
       prefsVersion = PrefGetAppPreferences (sysFileCDatebook, datebookPrefID,
          prefsP, &prefsSize, true);

       // If the preferences version is from a future release (as can happen when
       // going back and syncing to an older version of the device), treat it the
       // same as "not found" because it could be significantly different
       if ( prefsVersion > datebookPrefsVersionNum )
          prefsVersion = noPreferenceFound;

       if ( prefsVersion == noPreferenceFound ) {
          // Version 1 and 2 preferences
          prefsP->dayStartHour = defaultDayStartHour;
          prefsP->dayEndHour = defaultDayEndHour;
          prefsP->alarmPreset.advance = defaultAlarmPresetAdvance;
          prefsP->alarmPreset.advanceUnit = defaultAlarmPresetUnit;
          prefsP->saveBackup = defaultSaveBackup;
          prefsP->showTimeBars = defaultShowTimeBars;
          prefsP->compressDayView = defaultCompressDayView;
          prefsP->showTimedAppts = defaultShowTimedAppts;
          prefsP->showUntimedAppts = defaultShowUntimedAppts;
          prefsP->showDailyRepeatingAppts =
             defaultShowDailyRepeatingAppts;

          // We need to set up the note font with a default value for the system.
          FtrGet(sysFtrCreator, sysFtrDefaultFont, &defaultFont);
          haveDefaultFont = true;

          prefsP->v20NoteFont = (FontID)defaultFont;
       }

       if ((prefsVersion == noPreferenceFound) || (prefsVersion <
             datebookPrefsVersionNum)) {
          // Version 3 preferences
          prefsP->alarmSoundRepeatCount = defaultAlarmSoundRepeatCount;
          prefsP->alarmSoundRepeatInterval = defaultAlarmSoundRepeatInterval;
          prefsP->alarmSoundUniqueRecID = defaultAlarmSoundUniqueRecID;
          prefsP->noteFont = prefsP->v20NoteFont;

          // Fix up the note font if we copied from older preferences.
          if ((prefsVersion != noPreferenceFound) && (prefsP->noteFont ==
                largeFont))
             prefsP->noteFont = largeBoldFont;

          if (!haveDefaultFont)
             FtrGet(sysFtrCreator, sysFtrDefaultFont, &defaultFont);

          prefsP->apptDescFont = (FontID)defaultFont;
       }

       if ((prefsVersion == noPreferenceFound) || (prefsVersion <
             datebookPrefsVersionNum)) {
          // Version 4 preferences
          prefsP->alarmSnooze = defaultAlarmSnooze;
       }

       return prefsVersion;
    }
## Sound The Palm OS platform device has rudimentary sound generation. A square wave is generated directly from the 68328's PWM circuitry. There is frequency, duration, and volume control. Additionally, Palm OS 3.0 and higher support creating and playing standard MIDI sounds. The Palm OS sound manager provides an extendable API for playing custom sounds and system sounds, and for controlling default sound settings. Although the sound API accommodates multichannel design, the system provides only a single sound channel at present. The sound hardware can play only one simple tone at a time through an onboard piezoelectric speaker. Note that for a particular amplitude level, the Palm IIITM device is slightly louder than its predecessors. Single tones can be played by the SndDoCmd function and system sounds are played by the SndPlaySystemSound function. The end-user can control the amplitude of alarm sounds, game sounds, and system sounds by means of the Preferences application. System-supplied sounds include the Information, Warning, Error, Startup, Alarm, Confirmation, and Click sounds. Palm OS 3.0 introduces support for Standard MIDI Files (SMFs), format 0. An SMF is a note-by-note description of a tune-Palm OS doesn't support sampled sound, multiple voices, or complex "instruments." You can download the SMF format specification from the http://www.midi.org Web site. The alarm sounds used in the built-in Date Book application are SMFs stored in the System MIDI Sounds database and can be played by the SndPlaySmf function. All SMF records in the System MIDI Sounds database are available to the user. Developers can add their own alarm SMFs to this database as a way to add variety and personalization to their devices. You can use the sysFileTMidi file type and sysFileCSystem creator to open this database. Each record in the database is a single SMF, with a header structure containing the user-visible name. The record includes a song header, then a track header, followed by any number of events. The system only recognizes the keyDown, keyUp and tempo events in a single track; other commands which might be in the SMF are ignored. For more information, see the following: Adding a Standard MIDI File to a Database in this chapter. SndCallbackInfoType in the Palm OS Programmer's API Reference. SndMidiRecHdrType in the Palm OS Programmer's API Reference. You can use standard MIDI tools to create SMF blocks on desktop computers, or you can write code to create them on the Palm OS device. The sample code project "RockMusic," particularly the routines in the MakeSMF.c file, can be helpful to see how to create an SMF programmatically. Previous versions of Palm OS don't support SMFs or asynchronous notes; don't use the new routines or commands when the FtrGet function returns a system version of less than 0x03000000. Doing so will crash your application. See the section "The System Version Feature" for more information. ## Synchronous and Asynchronous Sound The SndDoCmd function executes synchronously or asynchronously according to the operation it is to perform. The sndCmdNoteOn and sndCmdFrqOn operations execute asynchronously; that is, they are non-blocking and can be interrupted by another sound command. In contrast, the sndCmdFreqDurationAmp operation is synchronous and blocking (it cannot be interrupted). The SndPlaySmf function is also synchronous and blocking; however, the Sound Manager polls the key queue periodically during playback and halts playback in progress if it finds events generated by user interaction with the screen, digitizer, or hardware-based buttons. Optionally, the caller can override this default behavior to specify that the SndPlaySmf function play the SMF to completion without being interrupted by user events. In Palm OS 4.0, three functions were added that allow you to interrupt a SndPlaySmf call that normally blocks: SndInterruptSmfIrregardless simply interrputs the currently-playing sound, while SndPlaySmfIrregardless and SndPlaySmfResourceIrregardless interrupt the current sound and also start a new one playing. ## Using the Sound Manager Before playing custom sounds that require a volume (amplitude) setting, your code needs to discover the user's current volume settings. To do so in Palm OS 3.X, pass one of the prefSysSoundVolume, prefGameSoundVolume, or prefAlarmSoundVolume selectors to the PrefGetPreference function. NOTE: See "Sound Preferences Compatibility Information" for important information regarding the correct use of sound preferences in various versions of Palm OS. You can pass the returned amplitude information to the SndPlaySmf function as one element of a SndSmfOptionsType parameter block. Alternatively, you can pass amplitude information to the SndDoCmd function as an element of a SndCommandType parameter block. To execute a sound manager command, pass to the SndDoCmd function a sound channel pointer (presently, only NULL is supported and maps to the shared channel), a pointer to a structure of SndCommandType, and a flag indicating whether the command should be performed asynchronously. To play SMFs, call the SndPlaySMF function. This function, which is new in Palm OS 3.0, is used by the built in Date Book application to play alarm sounds. To play single notes, you can use either of the SndPlaySMF or SndDoCmd functions. Of course, you can use the SndPlaySMF function to play a single MIDI note from an SMF. You can also use the SndDoCmd function to play a single MIDI note by passing the sndCmdNoteOn command selector to this function. To specify by frequency the note to be played, pass the sndCmdFrqOn command selector to the SndDoCmd function.You can pass the sndCmdQuiet selector to this function to stop playback of the current note. The system provides no specialized API for playing game sounds. Game sounds are implemented by the game developer using any appropriate element of the Sound Manager API. Games should observe the prefGameSoundVolume setting, as described in the section "Sound Preferences Compatibility Information." To play a default system sound, such as a click or an error beep, pass the appropriate system sound ID to the SndPlaySystemSound function, which will play that sound at the volume level specified by the user's system sound preference. For the complete list of system sound IDs, see the SoundMgr.h file provided by the Palm OS SDK. #### Adding a Standard MIDI File to a Database To add a format 0 standard MIDI file to the system MIDI database, you can use code similar to the AddSmfToDatabase example function shown in the following code listing. This function returns 0 if successful, and returns a non-zero value otherwise. To use a different database, pass different creator and type values to the DmOpenDatabaseByTypeCreator function. Listing 10.6 AddSmfToDatabase
    // Useful structure field offset macro
    #define prvFieldOffset(type, field) ((UInt32)(&((type*)0)->field))

    // returns 0 for success, nonzero for error
    Int16 AddSmfToDatabase(MemHandle smfH, Char* trackName)
    {
       Err           err = 0;
       DmOpenRef     dbP;
       UInt16*       recIndex;
       MemHandle     recH;
       UInt8*        recP;
       UInt8*        smfP;
       UInt32        bMidiOffset;
       UInt32        dwSmfSize;
       SndMidiRecHdrType       recHdr;

       bMidiOffset = sizeof(SndMidiRecHdrType) +
                          StrLen(trackName) + 1;
       dwSmfSize = MemHandleSize(smfH);

       recHdr.signature = sndMidiRecSignature;
       recHdr.reserved = 0;
       recHdr.bDataOffset = bMidiOffset;

       dbP = DmOpenDatabaseByTypeCreator(sysFileTMidi, sysFileCSystem,
                                              dmModeReadWrite | dmModeExclusive);
       if (!dbP)
          return 1;

       // Allocate a new record for the midi resource
       recIndex = dmMaxRecordIndex;
       recH = DmNewRecord(dbP, &recIndex, dwSmfSize + bMidiOffset);
       if ( !recH )
          return 2;

       // Lock down the source SMF and target record and copy the data
       smfP = MemHandleLock(smfH);
       recP = MemHandleLock(recH);

       err = DmWrite(recP, 0, &recHdr, sizeof(recHdr));
       if (!err) err = DmStrCopy(recP, prvFieldOffset(SndMidiRecType,
            name), trackName);
       if (!err) err = DmWrite(recP, bMidiOffset, smfP, dwSmfSize);

       // Unlock the pointers
       MemHandleUnlock(smfH);
       MemHandleUnlock(recH);

       //Because DmNewRecord marks the new record as busy,
       // we must call DmReleaseRecord before closing the database
       DmReleaseRecord(dbP, recIndex, 1);

       DmCloseDatabase(dbP);

       return err;
    }
#### Saving References to Standard MIDI Files To save a reference to a SMF stored in a particular database, save its record ID and the name of the database in which it is stored. Do not store the database ID between invocations of your application, because various events, such as a HotSync®, can invalidate database IDs. Using an invalid database ID can crash your application. #### Retrieving a Standard MIDI File From a Database Standard MIDI Files (SMFs) are stored as individual records in a MIDI record database-one SMF per record. Palm OS defines the database type sysFileTMidi for MIDI record databases. The system MIDI database, with type sysFileTMidi and creator sysFileCSystem, holds multiple system alarm sounds. In addition, your applications can create their own private MIDI databases of type sysFileTMidi and your own creator. To obtain a particular SMF, you need to identify the database in which it resides and the specific database record which holds the SMF data. The database record itself is always identified by record ID. The MIDI database in which it resides may be identified by name or by database ID. If you know the creator of the SMF, you can use the SndCreateMidiList utility function to retrieve this information. Alternatively, you can use the Data Manager record API functions to iterate through MIDI database records manually in search of this information. The SndCreateMidiList utility function retrieves information about Standard Midi Files from one or more MIDI databases. This information is returned as a table of entries. Each entry contains the name of an SMF; its unique record ID; and the database ID and card number of the record database in which it resides. Once you have the appropriate identifiers for the record and the database in which it resides, you need to open the MIDI database. If you have identified the database by type and creator, pass the sysFileTMidi type and an appropriate creator value to the DmOpenDatabaseByTypeCreator function. For example, to retrieve a SMF from the system MIDI database, pass type sysFileTMidi and creator sysFileCSystem. The DmOpenDatabaseByTypeCreator function returns a reference to the open database. If you have identified the database by name, rather than by creator, you'll need to discover its database ID in order to open it. The DmFindDatabase function returns the database ID for a database specified by name and card number. You can pass the returned ID to the DmOpenDatabase function to open the database and obtain a reference to it. Once you have opened the MIDI database, call DmFindRecordByID to get the index of the SMF record. To retrieve the record itself, pass this index value to either of the functions DmQueryRecord or DmGetRecord. When you intend to modify the record, use the DmGetRecord function-it marks the record as busy. When you intend to use the record in read-only fashion, use the DmQueryRecord function -it does not mark the record as busy. You must lock the handle returned by either of these functions before making further use of it. To lock the database record's handle, pass it to the MemHandleLock function, which returns a pointer to the locked record holding the SMF data. You can pass this pointer to the SndPlaySmf function in the smfP parameter to play the MIDI file. When you've finished using the record, unlock the pointer to it by calling the MemPtrUnlock function. If you've used DmGetRecord to open the record for editing, you must call DmReleaseRecord to make the record available once again to other callers. If you used DmQueryRecord to open the record for read-only use, you need not call DmReleaseRecord. Finally, close the database by calling the DmCloseDatabase function. ## Sound Preferences Compatibility Information The sound preferences implementation and API varies slightly among versions 1.0, 2.0, and 3.X of Palm OS. This section describes how to use sound preferences correctly for various versions of Palm OS. Because versions 2.0 and 3.X of Palm OS provide backward compatibility with previous sound preference mechanisms, applications written for an earlier version of the sound preferences API will get correct sound preference information from newer versions of Palm OS. However, it is strongly recommended that new applications use the latest API. #### Using Sound Preferences on All Palm OS Devices Because the user chooses sound preference settings, your application should respect them and adhere to their values. Further, you should always treat sound preferences as read-only values. At reset time, the sound manager reads stored preference values and caches them for use at run time. The user interface controls update both the stored preference values and the sound manager's cached values. The PrefSetPreference function writes to stored preference values without affecting cached values. New values are read at the next system reset. The system-use-only SndSetDefaultVolume function updates cached values but not stored preferences. Applications should avoid modifying stored preferences or cached values in favor of respecting the user's choices for preferences. #### Using Palm OS 1.0 Sound Preferences To read sound preference values in version 1.0 of Palm OS, call the PrefGetPreferences function to obtain the data structure shown in Listing 10.7. This SystemPreferencesTypeV10 structure holds the current values of all system-wide preferences. You must extract from this structure the values of the sysSoundLevel and alarmSoundLevel fields. These values are the only sound preference information that Palm OS version 1.0 provides. Each of these fields holds a value of either slOn (on) or slOff (off). Your code must interpret the values read from these fields as an indication of whether those volumes should be on or off, then map them to appropriate amplitude values to pass to Sound Manager functions: map the slOn selector to the sndMaxAmp constant (defined in SoundMgr.h) and map the slOff selector to the value 0 (zero). Listing 10.7 SystemPreferencesTypeV10 data structure
    typedef struct {
       UInt16 version;      // Version of preference info

       // International preferences
       CountryType country;  // Country the device is in
       DateFormatType dateFormat;  // Format to display date in
       DateFormatType longDateFormat;  // Format to display date in
       UInt8 weekStartDay;  // Sunday or Monday
       TimeFormatType timeFormat;  // Format to display time in
       NumberFormatType numberFormat;  // Format to display numbers in

       // system preferences
       UInt8 autoOffDuration;  // Time period before shutting off
       SoundLevelTypeV20 sysSoundLevel;  //error beeps
       SoundLevelTypeV20 alarmSoundLevel;   //alarm only
       Boolean hideSecretRecords;  // True to not display records with
                                     // their secret bit attribute set
       Boolean deviceLocked;         // Device locked until the system
                                     // password is entered
       UInt16  sysPrefFlags;   // Miscellaneous system pref flags copied into
                              // the global GSysPrefFlags at boot time.
       SysBatteryKind sysBatteryKind;
                                            // The type of batteries installed.
                                           // This is copied into the globals
                                           // GSysbatteryKind at boot time.

       } SystemPreferencesTypeV10;
#### Using Palm OS 2.0 Sound Preferences Version 2.0 of Palm OS introduces a new API for retrieving individual preference values from the system. You can pass any of the selectors prefSysSoundLevelV20, prefGameSoundLevelV20, or prefAlarmSoundLevelV20 to the PrefGetPreference function to retrieve individual amplitude preference values for alarm sounds, game sounds, or for overall (system) sound amplitude. As in Palm OS 1.0, each of these settings holds values of either slOn (on) or slOff (off), as defined in the Preferences.h file. Your code must interpret the values read from these fields as an indication of whether those volumes should be on or off, then map them to appropriate amplitude values to pass to Sound Manager functions: map the slOn selector to the sndMaxAmp constant (defined in SoundMgr.h file) and map the slOff selector to the value 0 (zero). For a complete listing of selectors you can pass to the PrefGetPreference function, see the Preferences.h file. #### Using Palm OS 3.X Sound Preferences Palm OS version 3.X enhances the resolution of sound preference settings by providing discrete amplitude levels for games, alarms, and the system overall. As usual, do not set preferences yourself, but treat them as read-only values indicating the proper volume level for your application to use. Palm OS 3.X defines the new sound amplitude selectors prefSysSoundVolume, prefGameSoundVolume, and prefAlarmSoundVolume for use with the PrefGetPreference function. The values this function returns for these selectors are actual amplitude settings that may be passed directly to Sound Manager functions. NOTE: The amplitude selectors used in previous versions of Palm OS (all ending with the Level suffix, such as prefGameSoundLevel) are obsoleted in version 3.0 of Palm OS and replaced by new selectors. The old selectors remain available in Palm OS 3.X to ensure backward compatibility and are suffixed V20 (for example, prefGameSoundLevelV20). #### Ensuring Sound Preferences Compatibility For greatest compatibility with multiple versions of the sound preferences mechanism, your application should condition its sound preference code according to the version of Palm OS on which it is running. See "The System Version Feature" for more information. When your application is launched, it should retrieve the system version number and save the results in its global variables (or equivalent structure) for use elsewhere. If the major version number is 3 (three) or greater, then use the 3.0 mechanism for obtaining sound amplitude preferences, since this reflects the user's selection most accurately. If the major version number is 2 (two), then use the 2.0 mechanism described in "Using Palm OS 2.0 Sound Preferences." If it is 1 (one), then use the 1.0 mechanism described in "Using Palm OS 1.0 Sound Preferences." Avoid calling new APIs (including new selectors) when running on older versions of Palm OS that do not implement them. In particular, note that violating any of the following conditions will cause your application to crash: Do not call either of the SndPlaySmf or SndCreateMidiList functions on versions of Palm OS prior to 3.0. Do not pass any selector other than sndCmdFreqDurationAmp to the SndDoCmd function on versions of Palm OS prior to 3.0. ## System Boot and Reset Any reset is normally performed by sticking a bent-open paper clip into the small hole in the back of the device. This hole, known as the "reset switch" is above and to the right of the serial number sticker (on Palm III devices). Depending on additional keys held down, the reset behavior varies, as follows: ## Soft Reset A soft reset clears all of the dynamic heap (Heap 0, Card 0). The storage heaps remain untouched. The operating system restarts from scratch with a new stack, new global variables, restarted drivers, and a reset communication port. All applications on the device receive a sysAppLaunchCmdSystemReset launch code. ## Soft Reset + Up Arrow Holding the up-arrow down while pressing the reset switch with a paper clip causes the same soft reset logic with the following two exceptions: The sysAppLaunchCmdSystemReset launch code is not sent to applications. This is useful if there is an application on the device that crashes upon receiving this launch code (not uncommon) and therefore prevents the system from booting. The OS won't load any system patches during startup. This is useful if you have to delete or replace a system patch database. If the system patches are loaded and therefore open, they cannot be replaced or deleted from the system. ## Hard Reset A hard reset is performed by pressing the reset switch with a paper clip while holding down the power key. This has all the effects of the soft reset. In addition, the storage heaps are erased. As a result, all programs, data, patches, user information, etc. are lost. A confirmation message is displayed asking the user to confirm the deletion of all data. The sysAppLaunchCmdSystemReset launch code is sent to the applications at this time. If the user selected the "Delete all data" option, the digitizer calibration screen comes up first. The default databases for the four main applications is copied out of the ROM. If you hold down the up arrow key when the "Delete all data" message is displayed, and then press the other four application buttons while still holding the up arrow key, the system is booted without reading the default databases for the four main applications out of ROM. ## System Reset Calls The system manager provides support for booting the Palm OS device. It calls SysReset to reset the device. This call does a soft reset and has the same effect as pressing the reset switch on the unit. Normally applications should not use this call. SysReset is used, for example, by the Sync application. When the user copies an extension onto the Palm OS device, the Sync application automatically resets the device after the sync is completed to allow the extension to install itself. ## Hardware Interaction Palm OS differs from a traditional desktop system in that it's never really turned off. Power is constantly supplied to essential subsystems and the on/off key is merely a way of bringing the device in or out of low-power mode. The obvious effect of pressing the on/off key is that the LCD turns on or off. When the user presses the power key to turn the device off, the LCD is disabled, which makes it appear as if power to the entire unit is turned off. In fact, the memory system, real-time clock, and the interrupt generation circuitry are still running, though they are consuming little current. This section looks at Palm OS power management, discussing the following topics: Palm OS Power Modes Guidelines for Application Developers Power Management Calls ## Palm OS Power Modes To minimize power consumption, the operating system dynamically switches between three different modes of operation: sleep mode, doze mode, and running mode. The system manager controls transitions between different power modes and provides an API for controlling some aspects of the power management. In sleep mode, the device looks like it's turned off: the display is blank, the digitizer is inactive, and the main clock is stopped. The only circuits still active are the real-time clock and interrupt generation circuitry. The device enters this mode when there is no user activity for a number of minutes or when the user presses the off button. The device comes out of sleep mode only when there is an interrupt, for example, when the user presses a button. To enter sleep mode, the system puts as many peripherals as possible into low-power mode and sets up the hardware so that an interrupt from any hard key or the real-time clock wakes up the system. When the system gets one of these interrupts while in sleep mode, it quickly checks that the battery is strong enough to complete the wake-up and then takes each of the peripherals, for example, the LCD, serial port, and timers, out of low-power mode. In doze mode, the main clock is running, the device appears to be turned on, the LCD is on, and the processor's clock is running but it's not executing instructions (that is, it's halted). When the processor receives an interrupt, it comes out of halt and starts processing the interrupt. The device enters this mode whenever it's on but has no user input to process. The system can come out of doze mode much faster than it can come out of sleep mode since none of the peripherals need to be woken up. In fact, it takes no longer to come out of doze mode than to process an interrupt. Usually, when the system appears on, it is actually in doze mode and goes into running mode only for short periods of time to process an interrupt or respond to user input like a pen tap or key press. In running mode, the processor is actually executing instructions. The device enters this mode when it detects user input (like a tap on the screen) while in doze mode or when it detects an interrupt while in doze or sleep mode. The device stays in running mode only as long as it takes to process the user input (most likely less than a second), then it immediately reenters doze mode. A typical application puts the system into running mode only about 5% of the time. To maximize battery life, the processor on the Palm OS platform device is kept out of running mode as much as possible. Any interrupt generated on the device must therefore be capable of "waking" up the processor. The processor can receive interrupts from the serial port, the hard buttons on the case, the button on the cradle, the programmable timer, the memory module slot, the real-time clock (for alarms), the low-battery detector, and any built-in peripherals such as a pager or modem. ## Guidelines for Application Developers Normally, applications don't need to be aware of power management except for a few simple guidelines. When an application calls EvtGetEvent to ask the system for the next event to process, the system automatically puts itself into doze mode until there is an event to process. As long as an application uses EvtGetEvent, power management occurs automatically. If there has been no user input for the amount of time determined by the current setting of the auto-off preference, the system automatically enters sleep mode without intervention from the application. Applications should avoid providing their own delay loops. Instead, they should use SysTaskDelay, which puts the system into doze mode during the delay to conserve as much power as possible. If an application needs to perform periodic work, it can pass a time out to EvtGetEvent; this forces the unit to wake up out of doze mode and to return to the application when the time out expires, even if there is no event to process. Using these mechanisms provides the longest possible battery life. ## Power Management Calls The system calls SysSleep to put itself immediately into low-power sleep mode. Normally, the system puts itself to sleep when there has been no user activity for the minimum auto-off time or when the user presses the power key. The SysSetAutoOffTime routine changes the auto-off time value. This routine is normally used by the system only during boot, and by the Preferences application. The Preferences application saves the user preference for the auto-off time in a preferences database, and the system initializes the auto-off time to the value saved in the preferences database during boot. While the auto-off feature can be disabled entirely by calling SysSetAutoOffTime with a time-out of 0, doing this depletes the battery. The current battery level and other information can be obtained through the SysBatteryInfo routine. This call returns information about the battery, including the current battery voltage in hundredths of a volt, the warning thresholds for the low-battery alerts, the battery type, and whether external power is applied to the unit. This call can also change the battery warning thresholds and battery type. ## The Microkernel Palm OS has a preemptive multitasking kernel that provides basic task management. Most applications don't need the microkernel services because they are handled automatically by the system. This functionality is provided mainly for internal use by the system software or for certain special purpose applications. In this version of the Palm OS, there is only one user interface application running at a time. The User Interface Application Shell (UIAS) is responsible for managing the current user-interface application. The UIAS launches the current user-interface application as a subroutine and doesn't get control back until that application quits. When control returns to the UIAS, the UIAS immediately launches the next application as another subroutine. See "Power Management Calls" for more information. Usually, the UIAS is the only task running. Occasionally though, an application launches another task as a part of its normal operation. One example of this is the Sync application, which launches a second task to handle the serial communication with the desktop. The Sync application creates a second task dedicated to the serial communication and gives this task a lower priority than the main user-interface task. The result is optimal performance over the serial port without a delay in response to the user-interface controls. Normally, there is no user interaction during a sync, so that the serial communication task gets all of the processor's time. However, if the user does tap on the screen, for example, to cancel the sync, the user-interface task immediately processes the tap, since it has a higher priority. Alternatively, the Sync application could have been written to use just one task, but then it would have to periodically poll for user input during the serial communication, which would hamper performance and user-interface response time. NOTE: Only system software can launch a separate task. The multi-tasking API is not available to developer applications. ## Retrieving the ROM Serial Number Some PalmTM devices, beginning with the Palm III product, hold a 12-digit serial number that identifies the device uniquely. (Earlier devices do not have this identifier.) The serial number is held in a displayable text buffer with no null terminator. The user can view the serial number in the Application Launcher application. (The pop-up version of the Launcher does not display the serial number.) The Application Launcher also displays to the user a checksum digit that you can use to validate user entry of the serial number. To retrieve the ROM serial number programmatically, pass the sysROMTokenSnum selector to the SysGetROMToken function. If the SysGetROMToken function returns an error, or if the returned pointer to the buffer is NULL, or if the first byte of the text buffer is 0xFF, then no serial number is available. The DrawSerialNumOrMessage function shown in Listing 10.8 retrieves the ROM serial number, calculates the checksum, and draws both on the screen at a specified location. If the device has no serial number, this function draws a message you specify. This function accepts as its input a pair of coordinates at which it draws output, and a pointer to the message it draws when a serial number is not available. Listing 10.8 DrawSerialNumOrMessage
    static void DrawSerialNumOrMessage(Int16 x, Int16 y, Char* noNumberMessage)
    {
       Char* bufP;
       UInt16* bufLen;
       Err retval;
       Int16    count;
       UInt8    checkSum;
       Char    checksumStr[2];
          // holds the dash and the checksum digit

       retval = SysGetROMToken (0, sysROMTokenSnum,
                                          (UInt8**) &bufP, &bufLen);
       if ((!retval) && (bufP) && ((UInt8) *bufP != 0xFF)) {
          // there's a valid serial number!
          // Calculate the checksum:  Start with zero, add each digit,
          // then rotate the result one bit to the left and repeat.
             checkSum = 0;
             for (count=0; count<bufLen; count++) {
                checkSum += bufP[count];
                checkSum = (checkSum<<1) | ((checkSum & 0x80) >> 7);
                }
          // Add the two hex digits (nibbles) together, +2
          // (range: 2 - 31 ==> 2-9, A-W)
          // By adding 2 to the result before converting to ascii,
          // we eliminate the numbers 0 and 1, which can be
          // difficult to distinguish from the letters O and I.
          checkSum = ((checkSum>>4) & 0x0F) + (checkSum & 0x0F) + 2;

          // draw the serial number and find out how wide it was
          WinDrawChars(bufP, bufLen, x, y);
          x += FntCharsWidth(bufP, bufLen);

          // draw the dash and the checksum digit right after it
          checksumStr[0] = '-';
          checksumStr[1] =
             ((checkSum < 10) ? (checkSum +'0'):(checkSum -10 +'A'));
          WinDrawChars (checksumStr, 2, x, y);
          }
          else // there's no serial number
          // draw a status message if the caller provided one
          if (noNumberMessage)
             WinDrawChars(noNumberMessage, StrLen(noNumberMessage),x, y);
    }
## Time The Palm OS platform device has a real-time clock and programmable timer as part of the 68328 processor. The real-time clock maintains the current time even when the system is in sleep mode (turned off). It's capable of generating an interrupt to wake the device when an alarm is set by the user. The programmable timer is used to generate the system tick count interrupts (100 times/second) while the processor is in doze or running mode. The system tick interrupts are required for periodic activity such as polling the digitizer for user input, key debouncing, etc. The date and time manager (called time manager in this chapter) provides access to both the 1-second and 0.01-second timing resources on the Palm OS device. The 1-second timer keeps track of the real-time clock (date and time), even when the unit is in sleep mode. The 0.01-second timer, also referred to as the system ticks, can be used for finer timing tasks. This timer is not updated when the unit is in sleep mode and is reset to 0 each time the unit resets. The basic time-manager API provides support for setting and getting the real-time clock in seconds and for getting the current system ticks value (but not for setting it). The system manager provides more advanced functionality for setting up a timer task that executes periodically or in a given number of system ticks. This section discusses the following topics: Using Real-Time Clock Functions Using System Ticks Functions ## Using Real-Time Clock Functions The real-time clock functions of the time manager include TimSetSeconds and TimGetSeconds. Real time on the Palm OS device is measured in seconds from midnight, Jan. 1, 1904. Call TimSecondsToDateTime and TimDateTimeToSeconds to convert between seconds and a structure specifying year, month, day, hour, minute, and second. ## Using System Ticks Functions The Palm OS device maintains a tick count that starts at 0 when the device is reset. This tick increments 100 times per second when running on the Palm OS device 60 times per second when running on the Macintosh under the Simulator For tick-based timing purposes, applications should use the macro SysTicksPerSecond, which is conditionally compiled for different platforms. Use the function TimGetTicks to read the current tick count. Although the TimGetTicks function could be used in a loop to implement a delay, it is recommended that applications use the SysTaskDelay function instead. The SysTaskDelay function automatically puts the unit into low-power mode during the delay. Using TimGetTicks in a loop consumes much more current. ## Floating-Point The Palm OS supports IEEE-754 single and double precision floating-point numbers declared with the C types float and double. Numbers of type float occupy four bytes and have an effective range of 1.17549e-38 to 3.40282e+38. Numbers of type double occupy eight bytes and have an effective range of 2.22507e-308 to 1.79769e+308. You can use basic arithmetic operations to add, subtract, multiply, and divide numbers of type float and double. Higher-level functions such as those in the standard C header file math.h are not part of the core OS; you must either write them yourself, or you must employ a third-party math library. The standard IEEE-754 special "non-number" values of NaN (not a number), +INF (positive infinity), and -INF (negative infinity) are generated as appropriate if you perform an operation that produces a result outside the range of numbers that can be represented. For instance, dividing a positive number by 0 returns +INF. The Float Manager contains functions that convert double-precision floating-point numbers to and from a string using scientific notation. It also contains FlpBufferCorrectedAdd and FlpBufferCorrectedSub, which perform the indicated operation and correct the result in those situations where the result should be zero but isn't due to the way that floating-point numbers are represented. All of the Float Manager functions that either accept or return a floating-point number require it to be declared as an FlpDouble. The Float Manager defines a union, FlpCompDouble, that you use to declare values that can be interpreted either as a double or as an FlpDouble. You use this union as shown here:
    double dblFlpCorrectedAdd (double d1, double d2, Int16 acc) {
        FlpCompDouble fcd1, fcd2, fcdResult;

        fcd1.d = d1;
        fcd2.d = d2;
        FlpBufferCorrectedAdd(&fcdResult.fd, fcd1.fd, fcd2.fd,
            acc);
        return fcdResult.d;
    }
NOTE: If you are using CodeWarrior, you have the option of using FlpAToF, FlpCorrectedAdd, and FlpCorrectedSub instead of FlpBufferAToF, FlpBufferCorrectedAdd, and FlpBufferCorrectedSub. These "non-buffer" functions all return their results directly, rather than updating a value pointed to by the first parameter. Because they return an FlpDouble-which is a struct-and because the GCC compiler's convention for returning structures from functions is incompatible with Palm OS, GCC users can only use the FlpBuffer... versions. In the rare event that you need to work with the binary representation of a double, the Float Manager also contains a number of functions and macros that allow you to obtain and in some cases alter the sign, mantissa, and exponent of a 64-bit floating-point number. See Chapter 33, "Float Manager," of the Palm OS Programmer's API Reference for the functions and macros that make up the Float Manager. The Float Manager, which was introduced in Palm OS 2.0, is sometimes referred to as the New Float Manager to distinguish it from the Float Manager that was part of Palm OS 1.0. The 1.0 Float Manager, which is less accurate and less convenient to use (simple operations such as addition require a call to a Float Manager function), remains in the ROM solely for backward compatibility; its functions are no longer publicly declared in the Palm OS SDK and should no longer be used. The functions in the old Float Manager all begin with "Fpl" rather than the current "Flp"; see Appendix C, "1.0 Float Manager," of the Palm OS Programmer's API Reference for the functions that make up the original Float Manager. ## Summary of System Features #####
Feature Manager Functions |
--- | ---
FtrGet FtrSet FtrPtrNew FtrPtrResize | FtrGetByIndex FtrUnregister FtrPtrFree
#####
Preferences Functions |
--- | ---
PrefGetAppPreferences PrefSetAppPreferences PrefGetPreference PrefOpenPreferenceDB PrefGetPreferences | PrefGetAppPreferencesV10 PrefSetAppPreferencesV10 PrefSetPreference PrefOpenPreferenceDBV10 PrefSetPreferences
#####
Sound Manager Functions |
--- | ---
SndCreateMidiList SndGetDefaultVolume SndPlaySmf SndPlaySmfResource SndPlaySystemSound | SndDoCmd SndInterruptSmfIrregardless SndPlaySmfIrregardless SndPlaySmfResourceIrregardless
#####
System Manager Functions |
--- | ---
System Dialogs |
SysGraffitiReferenceDialog SysKeyboardDialogV10 | SysKeyboardDialog
Power Management |
SysBatteryInfo SysSetAutoOffTime | SysBatteryInfoV20 SysTaskDelay
System Management |
SysLibFind SysRandom SysGremlins | SysLibLoad SysReset
Working With Strings and Resources
SysBinarySearch SysQSort SysCreatePanelList SysFormPointerArrayToStrings | SysInsertionSort SysCopyStringResource SysStringByIndex
Database Support |
SysCreateDataBaseList | SysCurAppDatabase
Error Handling |
SysErrString |
Event Handling |
SysHandleEvent |
System Information |
SysGetOSVersionString SysGetROMToken | SysGetStackInfo SysTicksPerSecond
#####
Time Manager Functions |
--- | ---
Allowing User to Change Date and Time
DayDrawDays DayDrawDaySelector DayHandleEvent | SelectDay SelectTimeV33 SelectDayV10
Changing the Date |
DateAdjust TimSetSeconds | TimAdjust
Converting to Date Format |
DateDaysToDate TimSecondsToDateTime | DateSecondsToDate
Converting Dates to Other Formats
DateToAscii DateToDays TimGetSeconds TimGetTicks | TimeToAscii DateToDOWDMFormat TimDateTimeToSeconds
Date Information |
DayOfMonth DaysInMonth | DayOfWeek
#####
Float Manager Functions |
--- | ---
FlpAToF FlpBufferCorrectedAdd FlpCorrectedAdd FlpFToA FlpSetNegative | FlpBufferAToF FlpBufferCorrectedSub FlpCorrectedSub FlpNegate FlpSetPositive