Example using the support package for LPC4088 DisplayModule

Dependencies:   DMBasicGUI DMSupport

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers AppImageViewer.cpp Source File

AppImageViewer.cpp

00001 /*
00002  *  Copyright 2014 Embedded Artists AB
00003  *
00004  *  Licensed under the Apache License, Version 2.0 (the "License");
00005  *  you may not use this file except in compliance with the License.
00006  *  You may obtain a copy of the License at
00007  *
00008  *    http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  *  Unless required by applicable law or agreed to in writing, software
00011  *  distributed under the License is distributed on an "AS IS" BASIS,
00012  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  *  See the License for the specific language governing permissions and
00014  *  limitations under the License.
00015  */
00016 
00017 
00018 #include "mbed.h"
00019 #include "AppImageViewer.h"
00020 #include "lpc_swim_font.h"
00021 #include "lpc_swim_image.h"
00022 #include "Image.h"
00023 #include "image_data.h"
00024 
00025 /******************************************************************************
00026  * Defines and typedefs
00027  *****************************************************************************/
00028  
00029 #define BOX_SIDE   192 //256
00030  
00031 #define BTN_WIDTH  40
00032 #define BTN_HEIGHT 40
00033 #define BTN_OFF    20
00034  
00035 /******************************************************************************
00036  * Global variables
00037  *****************************************************************************/
00038 
00039 /******************************************************************************
00040  * Private functions
00041  *****************************************************************************/
00042 
00043 static void buttonClicked(uint32_t x)
00044 {
00045   bool* done = (bool*)x;
00046   *done = true;
00047 }
00048 
00049 void AppImageViewer::draw()
00050 {
00051     // Prepare fullscreen
00052     swim_window_open(_win, 
00053                    _disp->width(), _disp->height(),         // full size
00054                    (COLOR_T*)_fb1,
00055                    0,0,_disp->width()-1, _disp->height()-1, // window position and size
00056                    0,                                       // border
00057                    BLACK, BLACK, BLACK);                    // colors: pen, backgr, forgr
00058 
00059     _btn = new ImageButton(_win->fb, _win->xpmax - BTN_OFF - BTN_WIDTH, _win->ypmax - BTN_OFF - BTN_HEIGHT, BTN_WIDTH, BTN_HEIGHT);
00060     _btn->loadImages(img_ok, img_size_ok);
00061     // Copy everything onto the back buffer
00062     memcpy(_fb2, _fb1, _disp->fbSize());
00063 }
00064 
00065 void AppImageViewer::load(const char* file)
00066 {
00067     Image::ImageData_t pre = {0};
00068     
00069     int res = Image::decode(file, Image::RES_16BIT, &pre);
00070     if (res == 0) {
00071         DMBoard::instance().logger()->printf("[ImageLoader] Preparing %s\n", file);
00072         Image::ImageData_t* data = _mailbox.alloc(osWaitForever);        
00073         if (data != NULL) {
00074             *data = pre;
00075             _mailbox.put(data);
00076         } else {
00077             DMBoard::instance().logger()->printf("[ImageLoader] Failed to get memory to prepare %s\n", file);
00078         }
00079     }
00080 }
00081 
00082 static bool recursiveProcessFS(char* buff, const char* name, unsigned int maxLen, AppImageViewer* app, int depth, int maxDepth)
00083 {
00084   if (depth > maxDepth) {
00085     return true;
00086   }
00087   uint32_t len = strlen(buff);
00088   if (len > 0) {
00089     if (buff[len - 1] != '/') {
00090       buff[len++] = '/';
00091       buff[len] = '\0';
00092     }
00093   }
00094   if ((strlen(name) + len) >= maxLen) {
00095     // avoid memory overwrite due to too long file path
00096     return true;
00097   }
00098   strcat(buff, name);
00099   len += strlen(name);
00100 
00101   DIR *d = opendir(buff);
00102   bool result = true; // success
00103   if (d != NULL) {
00104     struct dirent *p;
00105     while (result && ((p = readdir(d)) != NULL)) {
00106       result = recursiveProcessFS(buff, p->d_name, maxLen, app, depth+1, maxDepth);
00107       buff[len] = '\0';
00108     }
00109     closedir(d);
00110   } else {
00111     // a file
00112     if (len > 3) {
00113       if ((strncasecmp(buff+len-4, ".bmp", 4)==0) ||
00114           (strncasecmp(buff+len-4, ".png", 4)==0) ||
00115           (strncasecmp(buff+len-4, ".raw", 4)==0)) {
00116         DMBoard::instance().logger()->printf("[ImageLoader] found %s\n", buff);
00117         app->load(buff);
00118       }
00119     }
00120   }
00121   return result;
00122 }
00123 
00124 static void loaderTask(void const* args)
00125 {
00126   char* buff = (char*)malloc(512);
00127   if (buff != NULL)
00128   {
00129     DMBoard::instance().logger()->printf("Recursive list of file and folders in /mci/\n");
00130     buff[0] = '\0';
00131     recursiveProcessFS(buff, "/mci/", 512, (AppImageViewer*)args, 0, 2);
00132     DMBoard::instance().logger()->printf("Recursive list of file and folders in /usb/\n");
00133     buff[0] = '\0';
00134     recursiveProcessFS(buff, "/usb/", 512, (AppImageViewer*)args, 0, 2);
00135     DMBoard::instance().logger()->printf("Recursive list of file and folders in /qspi/\n");
00136     buff[0] = '\0';
00137     recursiveProcessFS(buff, "/qspi/", 512, (AppImageViewer*)args, 0, 2);
00138     free(buff);
00139   }
00140   DMBoard::instance().logger()->printf("loaderTask done\n");
00141 }
00142 
00143 /******************************************************************************
00144  * Public functions
00145  *****************************************************************************/
00146 
00147 AppImageViewer::AppImageViewer() : _disp(NULL), _win(NULL), _fb1(NULL), _fb2(NULL), _btn(NULL), _active(0)
00148 {
00149 }
00150 
00151 AppImageViewer::~AppImageViewer()
00152 {
00153     teardown();
00154 }
00155 
00156 bool AppImageViewer::setup()
00157 {
00158     _disp = DMBoard::instance().display();
00159     _win = (SWIM_WINDOW_T*)malloc(sizeof(SWIM_WINDOW_T));
00160     _fb1 = _disp->allocateFramebuffer();
00161     _fb2 = _disp->allocateFramebuffer();
00162 
00163     return (_win != NULL && _fb1 != NULL && _fb2 != NULL);
00164 }
00165 
00166 void AppImageViewer::runToCompletion()
00167 {
00168     // Alternative 1: use the calling thread's context to run in
00169     bool done = false;
00170     draw();
00171     _btn->setAction(buttonClicked, (uint32_t)&done);
00172     void* oldFB = _disp->swapFramebuffer(_fb1);
00173 
00174     _active = 1;
00175     
00176     Thread* tLoader = new Thread(osPriorityNormal, 8192);
00177     tLoader->start(callback(loaderTask, this));
00178     
00179     bool first = true;
00180     Timer t;
00181     while(!done) {
00182       osEvent evt = _mailbox.get(1000);
00183       if (evt.status == osEventMail) {
00184         COLOR_T* fb;
00185         if (_active == 1) {
00186           // render on the second frame buffer
00187           fb = (COLOR_T*)_fb2;
00188         } else {
00189           // render on the first frame buffer
00190           fb = (COLOR_T*)_fb1;
00191         }
00192         _win->fb = fb;
00193         Image::ImageData_t* data = (Image::ImageData_t*)evt.value.p;
00194         if ((data->width < _disp->width()) || (data->height < _disp->height())) {
00195           // clear display if the image isn't fullscreen
00196           memset(_win->fb, 0, _disp->fbSize());
00197         }
00198         swim_put_image_xy(_win, (COLOR_T*)data->pixels, data->width, data->height, (_disp->width()-data->width)/2, (_disp->height()-data->height)/2);
00199         free(data->pointerToFree);
00200         _mailbox.free(data);
00201         if (first) {
00202           first = false;
00203           t.start();
00204         } else {
00205           while (t.read_ms() < 2000) {
00206             ThisThread::sleep_for(100);
00207           }
00208         }
00209         _disp->setFramebuffer(fb);
00210         _active = (_active == 1 ? 2 : 1);
00211         t.reset();
00212       } else if (tLoader->get_state() == Thread::Deleted) {
00213         // No more images in the queue and the loader thread 
00214         // has completed its search
00215         break;
00216       }
00217     }
00218     
00219     delete tLoader;
00220     
00221     // The button must be drawn on the current framebuffer
00222     _btn->draw(_win->fb);
00223 
00224     // Wait for touches, but the AppLauncher is already listening
00225     // for new touch event and sends a signal to its thread which
00226     // is the same as runs this function so it is enough to wait
00227     // for that signal.
00228     TouchPanel* touch = DMBoard::instance().touchPanel();
00229     touch_coordinate_t coord;
00230     while(!done) {
00231       ThisThread::flags_wait_all(0x1);
00232       if (touch->read(coord) == TouchPanel::TouchError_Ok) {
00233         if (_btn->handle(coord.x, coord.y, coord.z > 0)) {
00234             _btn->draw();
00235         }
00236       }
00237     }
00238     
00239     // User has clicked the button, restore the original FB
00240     _disp->swapFramebuffer(oldFB);
00241     swim_window_close(_win);
00242 }
00243 
00244 bool AppImageViewer::teardown()
00245 {
00246     if (_win != NULL) {
00247         free(_win);
00248         _win = NULL;
00249     }
00250     if (_fb1 != NULL) {
00251         free(_fb1);
00252         _fb1 = NULL;
00253     }
00254     if (_fb2 != NULL) {
00255         free(_fb2);
00256         _fb2 = NULL;
00257     }
00258     if (_btn != NULL) {
00259         delete _btn;
00260         _btn = NULL;
00261     }
00262     return true;
00263 }
00264 
00265