Setting Up Your Own Objects

Creating a PPS object is as easy as calling open() on a file under /pps with the O_CREAT flag, which will create the PPS object if it doesn't already exist. Opening, closing, reading from, and writing to PPS objects uses the same mechanisms as performing those operations on other files in the filesystem. As shown in "Overview of the PPS Service" in this guide, as long as the data you write conforms to the format that PPS expects, you can write anything to your PPS objects.

Note: We recommend that you use the libpps API for encoding/decoding PPS data. These library functions make handling data easier, faster, and more reliable than using standard libc functions. For more information, see "PPS API reference" in the Persistent Publish/Subscribe Developer's Guide.

Location of PPS objects

When you develop your own apps, any objects that they use must be located at a path under the root PPS directory (/pps). Also, you must ensure that the filesystem grants write access to all PPS paths that your apps need to access. Filepath permissions are controlled by the Authorization Manager service, as described in the System Services Reference.

On Blackberry devices, some apps use objects accessed from a symbolic link at: /accounts/1000/appdata/application_ID/pps, where application_ID is the app's directory name, found under /apps on the target. This design is not supported by QNX systems—you must use objects under /pps.

Guidelines

You could design your program to interact with PPS objects in any variety of ways. Your design will include decisions such as whether to read objects in delta mode, how frequently to read, what data to write, whether or not to receive notifications in the form of pulses, and so on. Even more decisions come into play if you're designing a system that communicates through PPS using server objects.

Here are the basic steps for setting up your own PPS objects, whether you're designing a new program that interacts with PPS objects or adding that capability to an existing program:

  1. Make sure your program includes the fcntl.h and sys/pps.h header files.
  2. Open the PPS object as if it were a file. For example, to make an open call on an existing object:

    open("/pps/myobject", O_RDWR);

    This will open myobject with read and write privileges.

    If you're opening a PPS object that doesn't already exist, include the O_CREAT flag:

    open("/pps/an-object", O_RDWR | O_CREAT);

    Here we're including both O_RDWR and O_CREAT in one field with the bitwise OR operation.

  3. If you need to make a new directory, you can use the mkdir() function. For example, to create a directory called myservice under /pps/services/:

    mkdir("/pps/services/myservice", S_IWUSR | S_IWGRP | S_IWOTH | S_IRUSR 
           | S_IRGRP | S_IROTH);

    This will create your directory and assign read and write privileges for all users.

  4. Now you probably want to perform a read or write. Remember to use the pps_encoder_*() and pps_decoder_*() functions for handling your data.
  5. Eventually you'll need to close the PPS object before your program terminates. You can do this simply by calling close().

Interacting with your PPS objects

The basic "building blocks" you'll use for interacting with PPS objects are relatively few:

But you'll find many possibilities of combining these together, combining them with synchronization techniques (mutual exclusion locks, condition variables, etc...), and employing various ways to perform the same tasks. Again, see the Persistent Publish/Subscribe Developer's Guide for guidance.

Mutexes

How you'll use mutexes and other synchronization tools is up to you and depends on the needs of your program. Mutexes are used to ensure coherency between two parallel threads: one is reading new data from PPS while the other is using existing data to update the display. In this case, mutexes ensure that one thread doesn't try to change attributes that the other thread is trying to use. Note that the synchronization needs of your programs may be different.