Real Time App

The example app described here, aims for users who want to integrate Date and Time function into their custom apps. The app retrieves both Date and Time in a common format, dd/mm/yyyy and hh/mm/ss respectively. There are two separate buttons available to individually show Date and Time, when pressed.

After completing this Example, user will learn how to:
  • Control the Network Time Protocol(NTP) used to update via WiFi
  • Get current date/time from NTP
  • Write date/time with a given format to a label widget

How it works in WiPhone Interface

This example can be found in WiPhone menu like; Tools -> Development -> Software Examples -> Real Time App. Once you select that app, the main activity page will gets open containing; a text header "RealTime App", two buttons showing "Date" and "Time" with caption Date/Time App in body, and "Back" button in the footer area of WiPhone Screen.

image1 image2

Implementation in Firmware

Identify Major Files & Functions

  1. GUI.h
  2. GUI.cpp
  3. typedef enum ActionID : uint16_t {}
  4. GUIMenuItem menu[xx] PROGMEM = {}
  5. void GUI::enterApp (ActionID_t app)
  6. processEvent (EventType event)
  7. redrawScreen (bool redrawAll)
  8. RealTimeApp :: showTimePress()
  9. RealTimeApp :: showDatePress()

Declaring a unique name for your app in GUI.h file

Search for "typedef enum ActionID" method in GUI.h and put your app name "GUI_APP_RealTimeApp" as Action ID at designated place`.

Adding App ID into Menu

Search for GUIMenuItem menu[45] PROGMEM in GUI.h and add an array line with following arguments in GUI Menu Item Method.

  1. Index for Picrures Demo App -> 44
  2. Index of Parent Menu -> 39
  3. Menu Name -> Real Time App
  4. argument empty -> ""
  5. argument empty -> ""
  6. Enumeration ID -> GUI_APP_RealTimeApp

{ 44, 39, "Real Time App", "", "", GUI_APP_RealTimeApp }

Adding App Class into Header File

Insert following class code into GUI.h file.

GUI.h:

class RealTimeApp : public WindowedApp,FocusableApp{
 public:
  RealTimeApp( LCD& disp, ControlState& state, HeaderWidget* header, FooterWidget* footer);
  virtual ~RealTimeApp();
  ActionID_t getId() { return GUI_APP_RealTimeApp; };
  appEventResult processEvent(EventType event);
  void redrawScreen(bool redrawAll = false);
  void showTimePress();
  void showDatePress();
  void changeState(int i);
  bool PERISTATE[2] = {false, false};
  int sel = 0;
  int xold,yold;
 protected:
  LabelWidget* label;
  static const int EXIT_CNT = 5;
  ButtonWidget* bbKeys[2];
  // uint8_t keyPressed[25];
  bool anyKeyPressed;
  //MultilineTextWidget* details;
  bool screenInited = false;
  const colorType redBg = 0xf9a6;         // 255, 55, 55
  const colorType redBorder = TFT_RED;
  const colorType greenBg = TFT_GREEN;
  const colorType greenBorder = 0x5c0;    // 0, 185, 0
  const colorType yellowBg = TFT_YELLOW;
  const colorType yellowBorder = 0xb580;  // 177, 177, 0
  const colorType greyBg = GRAY_50;
  const colorType greyBorder = GRAY_33;
  const colorType blueBg = GRAY_50 | TFT_BLUE;
  const colorType blueBorder = GRAY_33 | (TFT_BLUE >> 1);

};

Instantiating the App

Before defining the App classes, search for GUI::enterApp(ActionID_t app) in GUI.cpp file and append below line in switch statement to instantiate the App object.

case GUI_APP_RealTimeApp::
  // NOTE : THIS IS AN EXAMPLE REAL TIME APP
  runningApp = new RealTimeApp(*screen, state, header, footer);
  break;

The designated place to add above line within the switch statement in code can be found at enterApp Method in GUI.cpp.

Define App Constructor

A constructor method that we already instantiated in step above, needs to be defined first in GUI.CPP. In General, to get the current the Date/Time, you will need to use functionality of ntpClock object functions to extract Date and Time of device.

   RealTimeApp::RealTimeApp( LCD& lcd, ControlState& state, HeaderWidget* header, FooterWidget* footer)
  : WindowedApp(lcd, state, header, footer), FocusableApp(2) {
  header->setTitle("RealTime App");

  label = new LabelWidget(0, (lcd.height() - fonts[AKROBAT_EXTRABOLD_22]->height()) / 1.5, lcd.width(), fonts[AKROBAT_EXTRABOLD_22]->height(),
                                                  "Date/Time App", WHITE, BLACK, fonts[AKROBAT_EXTRABOLD_22], LabelWidget::CENTER);
  footer->setButtons(NULL, "Back");   //buttons
  // Create all the widgets
  const uint16_t spacing = 1;
  uint16_t xOff = spacing;
  uint16_t yOff = header->height();
  // KEYPAD
  // - row 1
  yOff = header->height() + 80;
  bbKeys[0] = new ButtonWidget((lcd.width() / 2 - 60 ), yOff, "Date", 120, 25, TFT_BLACK, greenBg, greenBorder);

  yOff = header->height() + 130;
  bbKeys[1] = new ButtonWidget((lcd.width() / 2 - 60), yOff, "Time", 120, 25, TFT_BLACK, greenBg, greenBorder);

}

Declare and Define other Methods

This segments will show us a way of adding source code of other functions/ methods used in RealTimeApp Example. We declare and define these methods within the firmware code to fully implement our example App and subsequently put in place in GUI.cpp file. These functions are defined outside the RealTimeApp class definition and thus presented here with scope resolution operator (::) as below:

  1. RealTimeApp :: showTimePress()
  2. RealTimeApp :: showDatePress()
  3. RealTimeApp::~RealTimeApp()
  4. RealTimeApp::changeState(int i)
  5. RealTimeApp::processEvent(EventType event)
  6. RealTimeApp::redrawScreen(bool redrawAll)

RealTimeApp :: showTimePress() To get the current Time of the device, this function uses ntpClock.getHour(),ntpClock.getMinute(),ntpClock.getSecond() to extract current time in string hh/mm/ss format.

      void RealTimeApp :: showTimePress() {

String show_time = "hh/mm/ss: " + String(ntpClock.getHour()) + "/" + String(ntpClock.getMinute()) + "/" + String(ntpClock.getSecond());
label = new LabelWidget(0, (lcd.height() - fonts[AKROBAT_EXTRABOLD_22]->height()) / 1.5, lcd.width(), fonts[AKROBAT_EXTRABOLD_22]->height(),
                        show_time.c_str(), WHITE, BLACK, fonts[AKROBAT_EXTRABOLD_22], LabelWidget::CENTER);

}

RealTimeApp :: showDatePress() To get the current Date of the device, this function uses ntpClock.getDay(),ntpClock.getMonth(),ntpClock.getYear() to extract current date in string dd/mm/yyyy format.

        void RealTimeApp :: showDatePress()
{
  String show_time = "dd/mm/yyyy: " + String(ntpClock.getDay()) + "/" + String(ntpClock.getMonth()) + "/" + String(ntpClock.getYear());
  label = new LabelWidget(0, (lcd.height() - fonts[AKROBAT_EXTRABOLD_22]->height()) / 1.5, lcd.width(), fonts[AKROBAT_EXTRABOLD_22]->height(),
                                                  show_time.c_str(), WHITE, BLACK, fonts[AKROBAT_EXTRABOLD_22], LabelWidget::CENTER);
}

RealTimeApp::~RealTimeApp() This function defines RealTimeApp's destructor to release memory after usage.

All widgets must be registered and deleted by WiPhoneApp destructor.

RealTimeApp::~RealTimeApp() {
delete label;
}

RealTimeApp::changeState(int i) This function accepts argument having values 0 and 1 for toggling Date and Time display by calling their corresponding functions.

void RealTimeApp::changeState(int i) {
  log_d("fn::changeState() %d", i);
  PERISTATE[i] = !PERISTATE[i];
  if (i == 0) {
    showDatePress();
  } else if (i == 1) {
    showTimePress();
  }

}

RealTimeApp::processEvent(EventType event); This function defines the app events that are detected when a button is pressed on WiPhone Keypad. In this method, User can select "Date" and "Time" by triggering up, down, right and left keys events. Pressing "Ok" button event will display current date or time depending upon the selected one.

appEventResult RealTimeApp::processEvent(EventType event) {
  if (LOGIC_BUTTON_BACK(event) ) {
        return EXIT_APP;
  }
  appEventResult res = DO_NOTHING;
  bool toggleSelect = false;
  if (IS_KEYBOARD(event)) {
        anyKeyPressed = true;
        switch (event) {
          case WIPHONE_KEY_UP:
                toggleSelect = true;
                break;
          case WIPHONE_KEY_SELECT:
          case  WIPHONE_KEY_OK:
                changeState(sel);
                break;
          case WIPHONE_KEY_LEFT:
                toggleSelect = true;
                break;
          case WIPHONE_KEY_RIGHT:
                toggleSelect = true;
                break;
          case WIPHONE_KEY_DOWN:
                toggleSelect = true;
                break;
          default:
                break;
        }
  }

  if ( toggleSelect ) {
        if ( sel == 0 ) sel = 1;
        else if ( sel == 1 ) sel = 0;
  }

  if ( toggleSelect )
        log_d("Select changed %d ", sel);

  res |= REDRAW_SCREEN;
  return res;
}

RealTimeApp::redrawScreen(bool redrawAll); This method is used whenever user wants to update/ clear GUI for this app. Calling this method will redraw the default main activity screen designed for the App.

 void RealTimeApp::redrawScreen(bool redrawAll) {
if (!this->screenInited) {
  redrawAll = true;
}

if (redrawAll) {
  lcd.fillRect(0, header->height(), lcd.width(), lcd.height() - header->height() - footer->height(), TFT_BLACK);
}

int x = bbKeys[sel]->getParentOffX();
int y = bbKeys[sel]->getParentOffY();
int w = bbKeys[sel]->width();
int h = bbKeys[sel]->height();

lcd.drawRect(x - 10, y - 10, w + 20, h + 20, TFT_WHITE);
if (xold != x or yold != y) {
  lcd.drawRect(xold - 10, yold - 10, w + 20, h + 20, TFT_BLACK);
}
xold = x;
yold = y;
for (int i = 0; i < sizeof(bbKeys) / sizeof(bbKeys[0]); i++) {
  ((GUIWidget*) bbKeys[i])->refresh(lcd, redrawAll || !screenInited);
}
((GUIWidget *) label)->redraw(lcd);
screenInited = true;

}