Developing WiPhone Custom Apps

This walkthrough serves as a simple guide for users, developing custom apps in WiPhone's Arduino firmware with working knowledge of C++. It also presents a layout for specific examples to follow in later part. This guide may cover the high level scope and resources exist in WiPhone’s firmware which are applicable to all example apps developed by the users but it may lacks the specific requirements for some apps. Specific requirements related to any particular demo app will appear in dedicated section to that particular app. If you learn how to develop embedded code using the Arduino IDE, you will find this document helpful in implementing WiPhone example programs. It is important to get things started, by following general procedure here as well as the specific instructions for each illustrated example. This will also help keep your code clean, and maintainable.

WiPhone Firmware Structure

WiPhone firmware is build on a root GUI class which contains all required objects and methods to use the other classes such as Widgets, Application and Menu Items. These classes are inherited from their base classes as below:

  • Widgets are inherited from the base class AbstractWidget
  • All Applications are inherited from the base class WiPhoneApp
  • All Menu Items are inherited from the base class MenuOption

Some applications may use the file system only, other may use LEDs, Long Range (LoRa) communication, or any other functionality of the firmware individually or in combination. However, all applications should use the LCD to interact with the user. Similarly, all widgets and applications have processEvent and redraw methods to take user inputs (key presses) and draw the current state on the display. Moreover, all menu items have an ActionID to know which application to open on click.

_images/flowdiagram.png

Firmware Layout in WiPhone

Memory Management

Applications are created dynamically in the memory on demand (i.e. when clicked in the menu), then destructed to free its object memory and returns it to the memory management system for reuse by the other applications. The reason for this is to efficiently utilize the small memory available. Therefore, applications cannot store their states within itself and state variables would be disposed on closing the window of the app. As a result, the ControlState class is used as a Singleton object in system-wide to manage the states of the applications. For example, the MessagesApp's state may be 'receiving a LoRa message' even if it is not currently created.

Demystifying WiPhone App Classes

It is necessary prior to understand available application classes for embedding your custom app code in WiPhone’s firmware. The app class must derive from ''WiPhoneApp'' or one of its derivatives ("WindowedApp" or "FocusableApp", or both). Let’s have a look at the core app classes and what they really mean in WiPhone’s context.

WiPhoneApp

A base class of all window classes within the WiPhone firmware. it handles basic window functionality such as the input focus, window size and position, text metrics, and the message box by creating a window handle with the given LCD object. Beside that, it creates some labels, input widgets, sliders, rulers etc and stores within the given variables but not in a list. WiPhoneApp class behaves a common face of all classes of running applications. In other words, every running application is a WiPhoneApp class as well. This is because, the firmware should deal with every running application in a same way by using their common methods. To see the WiPhoneApp as a code snippet, we can look at the concrete class definition of an arbitrary application:

class PicturesDemoApp : public WiPhoneApp {
public:
  ...
  appEventResult processEvent(EventType event);
  void redrawScreen(bool redrawAll=false);
  ...
};

FocusableApp

Derived from WiPhoneApp class, it changes the focus through the focusable widgets (inputs, password inputs, sliders, etc.). It doesn't draw or change anything to screen. Only changes class variables within itself. FocusableApp is a common face of application classes which has one or more clickable and/or editable widgets. The applications with this class can use methods like nextFocus, getFocus to change the selected widget by clicking or editing it. To understand the FocusableApp as a code snippet, we can look at the concrete class definition of an arbitrary application:

class CreateMessageApp : public WindowedApp, FocusableApp {
public:
...
  appEventResult processEvent(EventType event); // this can call nextFocus method of the FocusableApp interface
  void redrawScreen(bool redrawAll=false);
...
};
_images/focusableapp.png

WindowedApp

Derived from WiPhoneApp class and extends its features, it also doesn't draw or change anything on screen. It only creates and stores information about the header and footer which resides at the top and bottom most lines of WiPhone display. It is the common face of application classes which has a header and a footer. ProcessEvent methods of such application classes changes the texts on the header and footer. Soem applications may have more than one interfaces like having both WindowedApp and FocusableApp faces. Similar to WiPhoneApp, the code snippet can be written only in class definitions of concrete application classes.

class MyApp : public WindowedApp, FocusableApp {
public:
  ...
  appEventResult processEvent(EventType event);
  void redrawScreen(bool redrawAll=false);
  ...
};
_images/MyApp-1.png

PopupApp

PopupApp is a concrete class which is used to display warnings on screen. Derived from both WindowedApp and FocusableApp, it extends their features. It implements the redraw function of the base class and draws a rectangle of popup window with all widgets inside. It also implements "process" method and processes button presses. Its code snippet is as given below.

void GUI::showPopup(char* caption, char* line1, char* line2, char* line3, char* btn1, char* btn2,
                    unsigned char* icon, int iconByteSize) {

  popupApp = new PopupApp(this->lcd, this->state, caption, btn1, btn2,
                          line1,
                          line2,
                          line3, icon, iconByteSize);
  popupApp->swapHeaderFooter(&header, &footer);
  //redrawScreen(false, false, true, false);
}

void GUI::redrawScreen(...){
  ...
  popupApp->redrawScreen(redrawAll);
  ...
}

appEventResult GUI::processEvent(uint32_t now, EventType event) {
  ...
  if(popupApp) {
    if(EXIT_APP == popupApp->processEvent(event)) {
      popupApp->swapHeaderFooter(&header, &footer); //return back to the previous header
      delete popupApp;
      popupApp = NULL;
  ...
}
_images/popupwidget.png

Code Insertion

In WiPhone firmware, code sections are isolated with line comments(//), to help users easily identify the areas where to put their codes. For example, sections such as Apps Section and Widgets Section are defined there. Users are expected to add new App class and new Widget class at the end of Apps Section and Widgets Section respectively. Moreover, Apps can be defined with the class having “App” as suffix while Widgets class having Widget as suffix". Besides adding App and Widgets, the user should create an object of the app class by using "new" keyword, assign it to the "runningApp" pointer within the corresponding "switch-case" area in the GUI::enterApp method as in this snippet:

runningApp = new MyApp(/*The parameters of the app here*/);

The runningApp lives in the singleton object of the GUI class type (i.e. it is accessed via "gui.runningApp" within the WiPhone.ino file). The GUI::processEvent calls the processEvent method of the runningApp and similarly the GUI::redraw method calls the redraw method of the running app in the GUI.cpp file.