The out-of-the-box demo application flashed on all display modules before they are shipped.

Dependencies:   DMBasicGUI DMSupport

This is the software that is flashed on the LPC4088 Display Modules before they are shipped from Embedded Artists.

Information

This project works on both the 4.3" and 5" display modules but requires different file systems to handle the different display resolutions.

For the 4.3" displays first drag-n-drop the media/fs_480_raw.fs5 (if you are using the new DAPLINK firmware use fs_480_raw.hex) file to the MBED drive and then drag-n-drop the demo itself. This way both the file system and software are up to date.

For the 5" displays first drag-n-drop the media/fs_800_raw.fsF (if you are using the new DAPLINK firmware use fs_800_raw.hex) file to the MBED drive and then drag-n-drop the demo itself. This way both the file system and software are up to date.

There is a prebuilt version of the demo binary here.

This is what it looks like on a 4.3" display:

/media/uploads/embeddedartists/demo480_cap_000.png /media/uploads/embeddedartists/demo480_cap_001.png /media/uploads/embeddedartists/demo480_cap_002.png /media/uploads/embeddedartists/demo480_cap_004.png /media/uploads/embeddedartists/demo480_cap_006.png /media/uploads/embeddedartists/demo480_cap_007.png /media/uploads/embeddedartists/demo480_cap_008.png
The first slide from the Slideshow:
/media/uploads/embeddedartists/demo480_cap_003.png
A couple of images from the Image Viewer
/media/uploads/embeddedartists/demo480_cap_009.png /media/uploads/embeddedartists/demo480_cap_010.png

Revision:
0:b94e330c98ac
Child:
2:229f88d6f56b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AppLauncherSpecial.cpp	Fri Mar 20 13:36:44 2015 +0000
@@ -0,0 +1,385 @@
+/*
+ *  Copyright 2014 Embedded Artists AB
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+
+#include "mbed.h"
+#include "AppLauncherSpecial.h"
+#include "lpc_swim_image.h"
+#include "lpc_swim_font.h"
+#include "Button.h"
+#include "ImageButton.h"
+#include "image_data.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+ 
+#define APP_PREFIX  "[Launcher*] "
+
+#define NO_APPLICATION  (-1)
+
+#define APP_SIGID_TOUCH  0x1
+
+/******************************************************************************
+ * Private variables
+ *****************************************************************************/
+
+static int appToLaunch = NO_APPLICATION;
+static osThreadId appThread;
+
+/******************************************************************************
+ * Private functions
+ *****************************************************************************/
+
+static void buttonClicked(uint32_t x)
+{
+    if (appToLaunch == NO_APPLICATION) {
+        appToLaunch = (int)x;
+    }
+}
+
+void AppLauncherSpecial::draw()
+{
+    // Prepare fullscreen
+    swim_window_open(_win, 
+                     _disp->width(), _disp->height(),         // full size
+                     (COLOR_T*)_fb,
+                     0,0,_disp->width()-1, _disp->height()-1, // window position and size
+                     0,                                     // border
+                     BLACK, WHITE, /*WHITE, BLACK,*/ BLACK);                    // colors: pen, backgr, forgr
+    //swim_set_title(_win, "Demo Program", WHITE);
+
+    swim_put_image(_win, _bgImg.pixels, _bgImg.width, _bgImg.height);
+    
+    if (_supportsCalibration) {
+      const char* msg = "(Press physical UserButton >2s to calibrate touch)";
+      int w, h;
+      swim_get_string_bounds(_win, msg, &w, &h);
+      swim_set_font_transparency(_win, 0); // 0=Transparent, 1=Opaque
+      swim_put_text_xy(_win, msg, (_disp->width()-w)/2, _disp->height()-(3*h)/2);
+      swim_set_font_transparency(_win, 1); // 0=Transparent, 1=Opaque
+    }
+    
+    for (int i = 0; i < _usedButtons; i++) {
+        _buttons[i]->draw();
+    }
+}
+
+void AppLauncherSpecial::onTouchEvent()
+{
+    _newTouchEvent = true;
+    osSignalSet(appThread, APP_SIGID_TOUCH);
+}
+
+void AppLauncherSpecial::onButtonEvent()
+{
+    _newButtonEvent = true;
+    osSignalSet(appThread, APP_SIGID_TOUCH);
+}
+
+static void onTimeoutEvent(void const* arg)
+{
+    *((bool*)arg) = true;
+    osSignalSet(appThread, APP_SIGID_TOUCH);
+}
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+
+AppLauncherSpecial::AppLauncherSpecial(int iconWidth, int iconHeight) : 
+    _disp(NULL), _win(NULL), _fb(NULL), _usedButtons(0), 
+    _resBg(NULL), _iconWidth(iconWidth), _iconHeight(iconHeight)
+{
+    _bgImg.pointerToFree = NULL;
+    _bgImg.pixels = NULL;
+    _currentTime[0] = '\0';
+
+    for (int i = 0; i < NumberOfButtons; i++) {
+        _buttons[i] = NULL;
+    }
+    bool r;
+    int n;
+    if (DMBoard::instance().touchPanel()->info(&r, &n, &_supportsCalibration) != TouchPanel::TouchError_Ok) {
+      _supportsCalibration = false;
+    }
+}
+
+AppLauncherSpecial::~AppLauncherSpecial()
+{
+    teardown();
+}
+
+bool AppLauncherSpecial::setup()
+{
+    RtosLog* log = DMBoard::instance().logger();
+
+    _disp = DMBoard::instance().display();
+    _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
+    _fb = _disp->allocateFramebuffer();
+    
+    if (_win == NULL || _fb == NULL) {
+        log->printf(APP_PREFIX"Failed to allocate memory for framebuffer\r\n");
+        return false;
+    }
+    
+    if (Image::decode(_resBg, Image::RES_16BIT, &_bgImg) != 0) {
+        log->printf(APP_PREFIX"Failed to load background image\n");
+        return false;
+    }
+    
+    return true;
+}
+
+void AppLauncherSpecial::runToCompletion()
+{
+    DMBoard* board = &DMBoard::instance();
+    RtosLog* log = board->logger();
+    
+    appThread = osThreadGetId();
+
+    // Draw something on the framebuffer before using it so that it doesn't look garbled
+    draw();
+    
+    // Start display in default mode (16-bit)
+    Display::DisplayError disperr = _disp->powerUp(_fb);
+    if (disperr != Display::DisplayError_Ok) {
+        log->printf(APP_PREFIX"Failed to initialize the display, got error %d\r\n", disperr);
+        return;
+    }
+    
+    // Render the current time in the upper right corner once every second
+    bool updateClock = false;
+    RtosTimer updateClockTimer(onTimeoutEvent, osTimerPeriodic, &updateClock);
+    updateClockTimer.start(1000);
+    int clockXOff, clockYOff;
+    swim_get_string_bounds(_win, "Fri Mar 20 10:32:58 2015", &clockXOff, &clockYOff);
+    clockXOff = _win->xpvmax - clockXOff - 20;
+    clockYOff = 5;
+    
+    // To keep track of the button pushes
+    bool buttonPressed = false;
+    bool buttonTimeout = false;
+    InterruptIn button(P2_10);
+    button.rise(this, &AppLauncherSpecial::onButtonEvent);
+    button.fall(this, &AppLauncherSpecial::onButtonEvent);
+    RtosTimer  buttonTimer(onTimeoutEvent, osTimerOnce, &buttonTimeout);
+    
+    // To prevent the "exit" click of a launched application to launch
+    // a new application. This could happen on a multitouch display if
+    // the launched applications' exit/ok/cancel button is located on
+    // top of one of the buttons in the launcher.
+    Timer tExit;
+    tExit.start();
+    
+    // Wait for touches
+    TouchPanel* touch = board->touchPanel();
+    FunctionPointer* fpOld = touch->setListener(new FunctionPointer(this, &AppLauncherSpecial::onTouchEvent));
+    touch_coordinate_t coord;
+    while (true) {
+        Thread::signal_wait(APP_SIGID_TOUCH);
+        if (_newTouchEvent) {
+          if (buttonPressed) {
+            // cancel
+            buttonPressed = false;
+            buttonTimer.stop();
+          }
+          _newTouchEvent = false;
+          if (touch->read(coord) != TouchPanel::TouchError_Ok) {
+            log->printf("Failed to read touch coordinate\n");
+            continue;
+          }
+          // Process the touch coordinate for each button
+          for (int i = 0; i < NumberOfButtons; i++) {
+            if (_buttons[i] != NULL) {
+              if (_buttons[i]->handle(coord.x, coord.y, coord.z > 0)) {
+                _buttons[i]->draw();
+              }
+            }
+          }
+        } else if (buttonTimeout) {
+          if (board->buttonPressed()) {
+            appToLaunch = CalibrationApp;
+          }
+          buttonPressed = false;
+          buttonTimeout = false;
+        } else if (_newButtonEvent) {
+          _newButtonEvent = false;
+          if (board->buttonPressed()) {
+            buttonPressed = true;
+            buttonTimer.start(2000);
+          } else {
+            buttonPressed = false;
+            buttonTimer.stop();
+          }
+          continue;
+        } else if (updateClock) {
+          updateClock = false;
+          time_t seconds = time(0);
+          sprintf(_currentTime, "%-25s", ctime(&seconds));
+          swim_put_text_xy(_win, _currentTime, clockXOff, clockYOff);
+          continue;
+        }
+        
+        if (appToLaunch != NO_APPLICATION) {
+          if (tExit.read_ms() < 500) {
+            appToLaunch = NO_APPLICATION;
+            continue;
+          }
+          App* a = NULL;
+          if (_callback != NULL) {
+            a = _callback(appToLaunch);
+          }
+          if (a != NULL) {
+            if (a->setup()) {
+              a->runToCompletion();
+              a->teardown();
+            }
+            delete a;            
+          }
+          tExit.reset();
+          appToLaunch = NO_APPLICATION;
+        }
+    }
+    
+    // restore old touch listener (get our listener in return)
+    fpOld = touch->setListener(fpOld);
+    delete fpOld;
+}
+
+bool AppLauncherSpecial::teardown()
+{
+    if (_win != NULL) {
+        free(_win);
+        _win = NULL;
+    }
+    if (_fb != NULL) {
+        free(_fb);
+        _fb = NULL;
+    }
+    for (int i = 0; i < NumberOfButtons; i++) {
+        _buttons[i] = NULL;
+        if (_buttons[i] != NULL) {
+            delete _buttons[i];
+            _buttons[i] = NULL;
+        }
+    }
+    if (_bgImg.pointerToFree != NULL) {
+        free(_bgImg.pointerToFree);
+        _bgImg.pointerToFree = NULL;
+    }    
+    return true;
+}
+
+void AppLauncherSpecial::setAppCreatorFunc(App*(*callback)(uint32_t buttonID))
+{
+    _callback = callback;
+}
+
+bool AppLauncherSpecial::addButton(uint32_t buttonID, const char* caption)
+{
+    int idx = _usedButtons++;
+    int xspace = ((_disp->width() - ButtonColumns * ButtonWidth) / (ButtonColumns + 1));
+    int yspace = ((_disp->height() - TitleHeight - ButtonRows * ButtonHeight) / (ButtonRows + 1));
+    
+    _buttons[idx] = new Button(caption, (COLOR_T*)_fb, 
+                              xspace + (ButtonWidth + xspace)*(idx%ButtonColumns), 
+                              TitleHeight + yspace + (ButtonHeight + yspace)*(idx/ButtonColumns), 
+                              ButtonWidth, ButtonHeight);
+    _buttons[idx]->setAction(buttonClicked, buttonID);
+    //_buttons[idx]->draw();
+    return true;
+}
+
+bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* imgUp, const char* imgDown)
+{
+    return addImageButton(buttonID, NULL, BLACK, imgUp, imgDown);
+}
+
+bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const char* imgUp, const char* imgDown)
+{
+    int idx = _usedButtons++;
+    int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1));
+    int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1));
+    
+    ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
+                              xspace + (_iconWidth + xspace)*(idx%ButtonColumns), 
+                              TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), 
+                              _iconWidth, _iconHeight, caption, color);
+    if (img->loadImages(imgUp, imgDown)) {
+      _buttons[idx] = img;
+      _buttons[idx]->setAction(buttonClicked, buttonID);
+      //_buttons[idx]->draw();
+      return true;
+    } else {
+      //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
+      return false;
+    }
+}
+
+bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize)
+{
+    return addImageButton(buttonID, NULL, BLACK, imgUp, imgUpSize, imgDown, imgDownSize);
+}
+
+bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, const unsigned char* imgUp, unsigned int imgUpSize, const unsigned char* imgDown, unsigned int imgDownSize)
+{
+    int idx = _usedButtons++;
+    int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1));
+    int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1));
+    
+    ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
+                              xspace + (_iconWidth + xspace)*(idx%ButtonColumns), 
+                              TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), 
+                              _iconWidth, _iconHeight, caption, color);
+    img->setTransparency(RED);
+    if (img->loadImages(imgUp, imgUpSize, imgDown, imgDownSize)) {
+      _buttons[idx] = img;
+      _buttons[idx]->setAction(buttonClicked, buttonID);
+      //_buttons[idx]->draw();
+      return true;
+    } else {
+      //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
+      return false;
+    }
+}
+
+bool AppLauncherSpecial::addImageButton(uint32_t buttonID, const char* caption, COLOR_T color, Resource* resUp, Resource* resDown)
+{
+    int idx = _usedButtons++;
+    int xspace = ((_disp->width() - ButtonColumns * _iconWidth) / (ButtonColumns + 1));
+    int yspace = ((_disp->height() - TitleHeight - ButtonRows * _iconHeight) / (ButtonRows + 1));
+    
+    ImageButton* img =  new ImageButton((COLOR_T*)_fb, 
+                              xspace + (_iconWidth + xspace)*(idx%ButtonColumns), 
+                              TitleHeight + yspace + (_iconHeight + yspace)*(idx/ButtonColumns), 
+                              _iconWidth, _iconHeight, caption, color);
+    if (img->loadImages(resUp, resDown)) {
+      _buttons[idx] = img;
+      _buttons[idx]->setAction(buttonClicked, buttonID);
+      //_buttons[idx]->draw();
+      return true;
+    } else {
+      //DMBoard::instance().logger()->printf("Failed to load image for buttonID %u, %s[%s]\n", buttonID, imgUp, imgDown==NULL?"":imgDown);
+      return false;
+    }
+}
+
+void AppLauncherSpecial::addResource(Resources id, Resource* res)
+{
+    _resBg = res;
+}
+