Sample GUI for LPC4088. Base code to begin dev

Dependencies:   DMBasicGUI DMSupport

Fork of lpc4088_displaymodule_shipped_demo by Embedded Artists

Revision:
0:b94e330c98ac
Child:
4:a7cbb22e4348
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/AppImageViewer.cpp	Fri Mar 20 13:36:44 2015 +0000
@@ -0,0 +1,267 @@
+/*
+ *  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 "AppImageViewer.h"
+#include "lpc_swim_font.h"
+#include "lpc_swim_image.h"
+#include "Image.h"
+
+/******************************************************************************
+ * Defines and typedefs
+ *****************************************************************************/
+ 
+#define BTN_OFF    20
+ 
+/******************************************************************************
+ * Global variables
+ *****************************************************************************/
+
+/******************************************************************************
+ * Private functions
+ *****************************************************************************/
+
+static void buttonClicked(uint32_t x)
+{
+  bool* done = (bool*)x;
+  *done = true;
+}
+
+void AppImageViewer::draw()
+{
+    // Prepare fullscreen
+    swim_window_open(_win, 
+                   _disp->width(), _disp->height(),         // full size
+                   (COLOR_T*)_fb1,
+                   0,0,_disp->width()-1, _disp->height()-1, // window position and size
+                   0,                                       // border
+                   BLACK, BLACK, BLACK);                    // colors: pen, backgr, forgr
+
+    // Create (but don't show) the button
+    _btn = new ImageButton(_win->fb, _win->xpmax - BTN_OFF - _resOk->width(), _win->ypmax - BTN_OFF - _resOk->height(), _resOk->width(), _resOk->height());
+    _btn->loadImages(_resOk);
+    // Copy everything onto the back buffer
+    memcpy(_fb2, _fb1, _disp->fbSize());
+}
+
+void AppImageViewer::load(const char* file)
+{
+    Image::ImageData_t pre = {0};
+    
+    int res = Image::decode(file, Image::RES_16BIT, &pre);
+    if (res == 0) {
+        DMBoard::instance().logger()->printf("[ImageLoader] Preparing %s\n", file);
+        Image::ImageData_t* data = _mailbox.alloc(osWaitForever);        
+        if (data != NULL) {
+            *data = pre;
+            _mailbox.put(data);
+        } else {
+            DMBoard::instance().logger()->printf("[ImageLoader] Failed to get memory to prepare %s\n", file);
+        }
+    }
+}
+
+static bool recursiveProcessFS(char* buff, const char* name, unsigned int maxLen, AppImageViewer* app, int depth, int maxDepth)
+{
+  if (depth > maxDepth) {
+    return true;
+  }
+  uint32_t len = strlen(buff);
+  if (len > 0) {
+    if (buff[len - 1] != '/') {
+      buff[len++] = '/';
+      buff[len] = '\0';
+    }
+  }
+  if ((strlen(name) + len) >= maxLen) {
+    // avoid memory overwrite due to too long file path
+    return true;
+  }
+  strcat(buff, name);
+  len += strlen(name);
+
+  DIR *d = opendir(buff);
+  bool result = true; // success
+  if (d != NULL) {
+    struct dirent *p;
+    while (result && ((p = readdir(d)) != NULL)) {
+      result = recursiveProcessFS(buff, p->d_name, maxLen, app, depth+1, maxDepth);
+      buff[len] = '\0';
+    }
+    closedir(d);
+  } else {
+    // a file
+    if (len > 3) {
+      if ((strncasecmp(buff+len-4, ".bmp", 4)==0) ||
+          (strncasecmp(buff+len-4, ".png", 4)==0) ||
+          (strncasecmp(buff+len-4, ".raw", 4)==0)) {
+        DMBoard::instance().logger()->printf("[ImageLoader] found %s\n", buff);
+        app->load(buff);
+      }
+    }
+  }
+  return result;
+}
+
+static void loaderTask(void const* args)
+{
+  char* buff = (char*)malloc(512);
+  if (buff != NULL)
+  {
+    DMBoard::instance().logger()->printf("Recursive list of file and folders in /mci/\n");
+    buff[0] = '\0';
+    recursiveProcessFS(buff, "/mci/", 512, (AppImageViewer*)args, 0, 2);
+    DMBoard::instance().logger()->printf("Recursive list of file and folders in /usb/\n");
+    buff[0] = '\0';
+    recursiveProcessFS(buff, "/usb/", 512, (AppImageViewer*)args, 0, 2);
+    if (DMBoard::instance().display()->width() == 480) {
+      DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/480x272/\n");
+      buff[0] = '\0';
+      recursiveProcessFS(buff, "/qspi/480x272/", 512, (AppImageViewer*)args, 0, 1);
+    } else {
+      DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/800x480/\n");
+      buff[0] = '\0';
+      recursiveProcessFS(buff, "/qspi/800x480/", 512, (AppImageViewer*)args, 0, 1);
+    }
+    free(buff);
+  }
+  DMBoard::instance().logger()->printf("loaderTask done\n");
+}
+
+/******************************************************************************
+ * Public functions
+ *****************************************************************************/
+
+AppImageViewer::AppImageViewer() : _disp(NULL), _win(NULL), 
+   _fb1(NULL), _fb2(NULL), _btn(NULL), _active(0), _resOk(NULL)
+{
+}
+
+AppImageViewer::~AppImageViewer()
+{
+    teardown();
+}
+
+bool AppImageViewer::setup()
+{
+    _disp = DMBoard::instance().display();
+    _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
+    _fb1 = _disp->allocateFramebuffer();
+    _fb2 = _disp->allocateFramebuffer();
+
+    return (_win != NULL && _fb1 != NULL && _fb2 != NULL);
+}
+
+void AppImageViewer::runToCompletion()
+{
+    // Alternative 1: use the calling thread's context to run in
+    bool done = false;
+    draw();
+    _btn->setAction(buttonClicked, (uint32_t)&done);
+    void* oldFB = _disp->swapFramebuffer(_fb1);
+
+    _active = 1;
+    
+    Thread* tLoader = new Thread(loaderTask, this, osPriorityNormal, 8192);
+    
+    bool first = true;
+    Timer t;
+    while(!done) {
+      osEvent evt = _mailbox.get(1000);
+      if (evt.status == osEventMail) {
+        COLOR_T* fb;
+        if (_active == 1) {
+          // render on the second frame buffer
+          fb = (COLOR_T*)_fb2;
+        } else {
+          // render on the first frame buffer
+          fb = (COLOR_T*)_fb1;
+        }
+        _win->fb = fb;
+        Image::ImageData_t* data = (Image::ImageData_t*)evt.value.p;
+        swim_put_image_xy(_win, (COLOR_T*)data->pixels, data->width, data->height, (_disp->width()-data->width)/2, (_disp->height()-data->height)/2);
+        free(data->pointerToFree);
+        _mailbox.free(data);
+        if (first) {
+          first = false;
+          t.start();
+        } else {
+          while (t.read_ms() < 2000) {
+            Thread::wait(100);
+          }
+        }
+        _disp->setFramebuffer(fb);
+        _active = (_active == 1 ? 2 : 1);
+        t.reset();
+      } else if (tLoader->get_state() == Thread::Inactive) {
+        // No more images in the queue and the loader thread 
+        // has completed its search
+        break;
+      }
+    }
+    
+    delete tLoader;
+    
+    // The button must be drawn on the current framebuffer
+    _btn->draw(_win->fb);
+
+    // Wait for touches, but the AppLauncher is already listening
+    // for new touch event and sends a signal to its thread which
+    // is the same as runs this function so it is enough to wait
+    // for that signal.
+    TouchPanel* touch = DMBoard::instance().touchPanel();
+    touch_coordinate_t coord;
+    while(!done) {
+      Thread::signal_wait(0x1);
+      if (touch->read(coord) == TouchPanel::TouchError_Ok) {
+        if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
+            _btn->draw();
+        }
+      }
+    }
+    
+    // User has clicked the button, restore the original FB
+    _disp->swapFramebuffer(oldFB);
+    swim_window_close(_win);
+}
+
+bool AppImageViewer::teardown()
+{
+    if (_win != NULL) {
+        free(_win);
+        _win = NULL;
+    }
+    if (_fb1 != NULL) {
+        free(_fb1);
+        _fb1 = NULL;
+    }
+    if (_fb2 != NULL) {
+        free(_fb2);
+        _fb2 = NULL;
+    }
+    if (_btn != NULL) {
+        delete _btn;
+        _btn = NULL;
+    }
+    return true;
+}
+
+void AppImageViewer::addResource(Resources id, Resource* res)
+{
+    _resOk = res;
+}
+