BREWing with C++
In this article, we'll investigate the fundamentals of C++ programming for the BREW platform. This time out, you'll learn the fundamental structure of a BREW C++ application and discover the subset of C++ features that can be used while developing for BREW. We'll also design a basic C++ drawing application and code its foundation. This foundation will serve as the basis for exploring BREW user-interface design issues in future articles.
I assume you've read the Getting Started articles. If not, they can be found here.
C++ Basics for BREW
Figure 1 shows the header file containing the skeletal definition of the application class (
ShapeApp) for our drawing program. The first thing you're likely to notice is that
ShapeApp is derived from
AEEApplet is a
typedef for a
struct. Thus, via public inheritance and the default visibility of
struct members in C++, all of AEEApplet's members can be accessed directly from any ShapeApp member function.
Next, you can see that the
ShapeApp class definition includes 2 versions for each of the event handling function, the data initialization function, and the data freeing function. All of the public versions are declared
static while the protected versions are instance methods. The static versions provide
ShapeApp's interface to the Application Execution Environment (AEE). As shown in Figure 3, each of these static versions exist only to call the corresponding instance method. In this way, the application class acquires a
this pointer that can be used to implicitly access members of
ShapeApp, including the members of the inherited
As shown in Figure 2,
AEEClsCreateInstance() must be enclosed by an
extern "C" linkage block. Note that the static versions of both the event handler and
freeAppData() are specified in the call to
AEEApplet_New(). Subsequently, the static data initializer is called. Apart from these minor differences,
AEEClsCreateInstance() is identical to that specified for
HelloBREW in the previous article.
Figure 3 contains the remainder of the
ShapeApp implementation file. As you can see, the file does nothing but set up the framework for our drawing program. Later, we'll create event handling code and generally flesh out this skeleton. Before we can do that, however, we need to understand the limitations imposed on our use of standard C++ for coding BREW applications.
You can use C++, BUT...
Understandably, the minimalists among you may have gasped at the sight of our static event handler calling the member event handler. Clearly, the cost of the extra function call is incurred every time the AEE dispatches an event to
ShapeApp. At runtime then, this overhead might be incurred many thousands of times before the application is terminated. If speed is of the essence for your application, you might consider handling every event in the static event handler. The efficiency gain might far outweigh the convenience of having a
this pointer to work with, especially since only one instance of the application can be running at any given time. If, for example, you make
this pointer becomes unnecessary since
ShapeApp *pi can be used to access the members of the one and only application instance.
On the topic of efficiency, as defined in the standard, certain elements of the C++ language contribute substantial amounts of overhead, even if they are not used in a program (see this article). In an embedded environment where memory is scarce, an application may not be able to afford these costs.
To address this issue, a Japanese consortium has hammered out the Embedded C++ (EC++) specification. EC++ is a proper subset of standard C++ intended to meet the needs of the embedded development community. Essentially, EC++ is standard C++ without multiple inheritance, virtual base classes, templates, exception handling, run-time type identification, the
mutable specifier, namespaces, and new-style casts. Modern ARM C++ compilers support the EC++ dialect. Thus, if you restrict yourself to EC++, you should have no trouble compiling an application to run on a handset.
The Program Design
Figure 4 includes a simple UML (Unified Modeling Language) class diagram. For the sake of anyone unfamiliar with the notation, the diagram shows that
ShapeApp "is a"
AEEApplet that "has a"
List as a data member. This
List is composed of a number of
Shapes (pointers to
Shapes actually, since
Shape is an abstract base class (ABC) that cannot have concrete instances). Each
Shape "has a"
Color and every concrete
Shape must implement the pure virtual
Rectangles are possible concrete
Circle has a
Point instance for its center and each
Rectangle is specified by two
Point instances: its upper left corner (ulc) and its lower right corner (lrc). The intent of this example is to demonstrate that EC++ supports polymorphism (I've verified this by building the source code with ARM Developer Suite v1.2 and testing the executable on the Sharp Z800 handset). Admittedly, this design won't be winning any awards for code reusability.
The complete source code for this example can be obtained via the link included at the bottom of this article. The only part that I want to cover in detail in the remainder of this article is the drawing code that renders shapes on the device's display. This functionality resides in the
List and concrete shape classes, namely
In BREW, a color is stored in an
RGBVAL, which is a
typedef name for a 32-bit unsigned integer. The
Color class has an
RGBVAL as its sole data member. The class also provides public member functions for accessing the individual components of an RGBVAL; namely
uint8 getg(), and
uint8 getb(). These functions merely slice off the requested value by bit shifting the
RGBVAL according to the layout given by Figure 5. Note that the RGBVAL diagram shown on page 736 of the SDK 1.0 API Reference is incorrect. The diagram has been corrected in the SDK 2.0 Reference though I have not checked the SDK 1.1 API Reference.
Recall from the discussion of Figure 4 above that the application class,
ShapeApp, maintains a
List instance that tracks
Shape pointers. As shown in Figure 6 below, the list class includes a public
update() instance method that is called from the application's event handler whenever a drawing event occurs. This
update() method receives the application's
IShell * so that an instance of the
IGraphics interface can be created through a call to
ISHELL_CreateInstance(). Please see the BREW API Reference for a description of the various
IGraphics API functions used throughout
In Figure 6, within the body of the
while(), you need to know that
CNode is a
struct nested within the
private visibility section. Further, the data part of a node consists of a
CShape * named
dat. Thus, the expression
pn->dat->getClr()->getr() returns the red component of the current
Still within the body of the loop, the expression
pn->dat->draw(pg) polymorphically calls the draw function pertaining to the current, concrete shape instance. Thus, a rectangle draws itself by using the passed in
IGraphics * to call
IGRAPHICS_DrawRect() and a circle similarly draws itself by calling
IGRAPHICS_DrawCircle(). Note that the calls to the
IGraphics color setting functions are contained within the body of the loop in order to capture the fact that each shape can have a different color.
So far, this applet does not require any string or image resources, beyond the application icons included within the .mif, so a BREW Applet Resource (.bar) file is unnecessary. If you've forgotten the details about creating a module information file (.mif), which is required for every applet, please review the Getting Started articles which can be found here. Note that I've included a .mif with the source code. Running the application on the emulator should result in the display looking as shown in the rightmost portion of Figure 7, above.
Next time, we'll begin enabling user-interaction with ShapeApp by experimenting with various user interface designs.
Download source: Shapes.zip (11KB)Instructions: (Assumes you have read the Getting Started articles.)
- Use the BREW Application Wizard to create a new project named 'shapeapp' under your BREW directory's 'Examples' directory.
- Delete the shapeapp.c file the wizard created for you.
- Unzip the source files to the shapeapp directory (include the .bid file).
- Use VC++'s file view to add the .h and .cpp files to the project.
- Copy the provided .mif file to your MIF directory.
- Build the application and run it using the emulator.
# # #
© Copyright 2002, Golden Creek Software Inc.