September 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

BREWing with C++

  • November 25, 2002
  • By Murray Bonner
  • Send Email »
  • More Articles »

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 - Click here for larger image

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. In aeeappgen.h, 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 AEEApplet struct.



Figure 2 - Click here for larger image

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.



Figure 3 - Click here for larger image

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 ShapeApp a struct, a 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

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 draw() function. Circles and Rectangles are possible concrete Shapes. Every 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 Circle and Rectangle.

Drawing Shapes



Figure 5 - Click here for larger image

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 getr(), 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 CList::Update().



Figure 6 - Click here for larger image

In Figure 6, within the body of the while(), you need to know that CNode is a struct nested within the CList class's 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 CShape's CColor instance.

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.

Running ShapeApp


Figure 7

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.)
  1. Use the BREW Application Wizard to create a new project named 'shapeapp' under your BREW directory's 'Examples' directory.
  2. Delete the shapeapp.c file the wizard created for you.
  3. Unzip the source files to the shapeapp directory (include the .bid file).
  4. Use VC++'s file view to add the .h and .cpp files to the project.
  5. Copy the provided .mif file to your MIF directory.
  6. Build the application and run it using the emulator.

# # #

© Copyright 2002, Golden Creek Software Inc.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel