Peripheral Test App¶
The example app described here, aims for users who want to integrate two of the WiPhone's built-in Peripherals including Vibrator and Keypad Backlit in their custom apps. It will help enable Users to develop different sort of applications which utilize these two features by showing how to control their ON / OFF state within the WiPhone firmware code.
- After completing this Example, user will learn how to:
- Use peripheral devices such as vibration and keypad backlight modules
- Connect general purpose IO pins to peripheral devices
- Use general purpose pins to start/stop or turn on/off peripheral devices
- Connect button widgets to general purpose IO pins
How it works in WiPhone Interface¶
This example can be found in WiPhone menu like; Tools -> Development -> Software Examples -> Peripheral Test. Once you select that app, the main activity page will open containing "Peri Test App" as title in header section and "Back" in bottom right corner of footer seciton. The main activity section displays two label buttons in center; "Vibration" and "Backlight". Background color for both these buttons are kept "Red" to signify they are in OFF state by default. User can select between them by switching through keypad arrow keys. When user selects and presses "Vibration" button, it will turn green and WiPhone will start vibrating, similarly, when user selects and presses "Backlight" button, it will turn green and the backlit of WiPhone Keypad will turn ON. Screenshot for this App activity is given below.
Implementation in Firmware¶
Identify Major Files & Functions¶
- GUI.h
- GUI.cpp
- typedef enum ActionID : uint16_t {}
- GUIMenuItem menu[xx] PROGMEM = {}
- processEvent (EventType event)
- changeState(int i)
- redrawScreen (bool redrawAll)
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_PeriTestApp" as Action ID at designated place`.
Adding App Class into Header File¶
Insert following class code into GUI.h file.
GUI.h:
class PeriTestApp : public WindowedApp {
public:
PeriTestApp( LCD& disp, ControlState& state, HeaderWidget* header, FooterWidget* footer);
virtual ~PeriTestApp();
ActionID_t getId() { return GUI_APP_PeriTestApp; };
appEventResult processEvent(EventType event);
void redrawScreen(bool redrawAll = false);
void changeState(int i);
bool PERISTATE[2] = {false, false};
int sel = 0;
int xold,yold;
protected:
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_PeriTestApp:
// NOTE : THIS IS AN EXAMPLE PERIPHERAL APP
runningApp = new PeriTestApp(*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. After that, other related functions to follow in order to fully implement our example App. Let’s add constructor function for class PeriTestApp.
GUI.cpp
PeriTestApp::PeriTestApp( LCD& lcd, ControlState& state, HeaderWidget* header, FooterWidget* footer)
: WindowedApp(lcd, state, header, footer) {
header->setTitle("Peri Test APP");
footer->setButtons(NULL, "Back");
// Create all the widgets
const uint16_t spacing = 1;
uint16_t xOff = spacing;
uint16_t yOff = header->height();
// KEYPAD
// - row 1
yOff = header->height() + 30;
bbKeys[0] = new ButtonWidget(20, yOff, "Vibration", 120, 25, TFT_BLACK, greyBg, greyBorder);
yOff = header->height() + 80;
bbKeys[1] = new ButtonWidget(20, yOff, "BackLight", 120, 25, TFT_BLACK, greyBg, greyBorder);
}
Declare and Define other Methods¶
This segments will show us a way of adding source code of other functions/ methods used in Peripheral Test 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 PeriTestApp class and thus presented here with scope resolution operator (::) as below:
- PeriTestApp::~PeriTestApp();
- PeriTestApp::changeState(int i);
- PeriTestApp::processEvent(EventType event);
- PeriTestApp::redrawScreen(bool redrawAll);
PeriTestApp::~PeriTestApp() This function defines PeriTestApp's destructor to release memory after usage. All widgets must be registered and deleted by WiPhoneApp destructor.
PeriTestApp::~PeriTestApp() {
// all widgets must be destroyed to release memory.
}
PeriTestApp::changeState(int i); changeState(int i) is a class to toggle the selected feature (vibration or backlit) state. It takes input parameter "i" as argument where i can iterate values between 0 - 1. To control the WiPhone's vibration feaure, user need to call "allDigitalWrite(VIBRO_MOTOR_CONTROL, HIGH/LOW)" while controlling keypad backlit, use "allDigitalWrite(KEYBOARD_LED, HIGH/LOW)" in your code.
void PeriTestApp::changeState(int i) {
log_d("fn::changeState() %d", i);
PERISTATE[i] = !PERISTATE[i];
if (i == 0) {
allDigitalWrite(VIBRO_MOTOR_CONTROL, PERISTATE[i]);
} else if (i == 1) {
allDigitalWrite(KEYBOARD_LED, !PERISTATE[i]);
}
}
PeriTestApp::processEvent(EventType event); This function defines the app events that are detected when a button is pressed on WiPhone Keypad. In this method, it can be seen that arrow key presses change the value of the "sel" which is input to changeState method on pressing WIPHONE_KEY_OK. Whenever user presses any key, the callback event invokes. User is required to handle any key press-related functions here.
appEventResult PeriTestApp::processEvent(EventType event) {
int lim = sizeof(PERISTATE) / sizeof(PERISTATE[0]);
if (LOGIC_BUTTON_BACK(event) ) {
allDigitalWrite(VIBRO_MOTOR_CONTROL, 0);
allDigitalWrite(KEYBOARD_LED, 1);
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);
for (int j = 0 ; j < sizeof(PERISTATE) / sizeof(PERISTATE[0]); j++) {
//replace this with analog read and color change
if (PERISTATE[j] == true) {
bbKeys[j]->setColors(TFT_BLACK, greenBg, greenBorder);
} else {
bbKeys[j]->setColors(TFT_BLACK, redBg, redBorder);
}
}
res |= REDRAW_SCREEN;
return res;
}
PeriTestApp::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 PeriTestApp::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);
}
screenInited = true;
}